Tag: cb_software

Parlay: A Paragraph Layout Library

Parlay is a C library for laying out out paragraphs to an in-memory buffer.

This current version is 0.1.

Summary

Parlay does one thing. It take some text (it could be plain text or a simple markup language), lays that text out in a paragraph, and creates an RGBA image of that paragraph in memory.

That’s it. That’s all it does. You give it paragraph text, you get back an image buffer.

It’s not something that exists only as part of some weird rendering pipeline. It is not built upon a massive foundational library. It doesn’t have multiple backends. It doesn’t have plugins. It’s not scriptable. It’s not part of a framework. It stands alone.

The only input to Parlay is the text you want to render, some style information, including the font to use, and a few layout options. The only output is an RGBA image buffer.

Its only dependencies are FreeType and, optionally, MiniXML.

Features

  • Lays out and renders text to an in-memory buffer
  • Supports any True Type or Type 1 font that FreeType library supports
  • Allows user to register font files (it doesn’t rely on system fonts)
  • Renders text in different styles like italic and bold, different font sizes, and different colors
  • Supports outlines on characters
  • Supports highlighting characters (i.e., as with a highlighting pen)
  • Has basic layout control like maximum width and paragraph alignment
  • Supports Unicode and the UTF-8 encoding
  • Implements a simple XML-based markup language for specifying styles
  • Does not have a lot of dependencies: just FreeType and optionally MiniXML

Limitations

  • Currently only supports left-to-right text
  • Probably does not support combining characters, though I’ve never actually tried it
  • Requires user to register font files (it doesn’t use system fonts at all)
  • Supports ONLY the UTF-8 encoding
  • Does not yet support some basic styles like underline
  • Does not yet support grayscale buffers, though of course you can render gray characters to an RGB buffer
  • Does not currently support kerning

License

Parlay is free to use and distribute, subject to a BSD-Style license. See the file LICENSE.txt for details.

For binary distributions (i.e., if you distribute software that uses Parlay) I consider a note saying that the software uses Parlay, with a clickable link back to the official home page of Parlay, to satisfy the second bullet point of license.

http://blog.aerojockey.com/post/parlay

Source distributions should include the license file and not rely on a link.

Downloading

You can download Parlay from GitHub.

https://github.com/aerojockey/parlay

Building

Parlay is highly portable C. I think the only compatibility drama might come from a pair of inline functions. I don’t expect you’ll have trouble building it on any system that FreeType supports.

Unless you’re building libparlay.so for some kind of Linux distro, I recommend you just add the source files to your project and compile it in. You need to build it with the FreeType library, version 2. If you want the simple markup language, you’ll also need to build with MiniXML.

There is only one configuration option, PARLAY_USE_MINIXML, which specifies whether to build the function parlay_markup_text, which requires MiniXML. You can modify this option at the top of parlay.h, or define it on your compiler’s command line.

I make no guarantees about thread safety at this point. The functions parlay_register_font and parlay_init are certainly not thread safe, but you should probably be calling those during initialization anyway. I suspect that if you linked Parlay with a thread-safe version of Freetype, then the functions parlay_plain_text and parlay_markup_text would be thread-safe. But it wasn’t a design goal of mine to make them thread-safe, so no guarantees.

Usage

The API is very simple at this point: after initializating and registering fonts, you call one function to get one rendered buffer.

(The underlying implementation allows for more exciting possibilities like streaming text into a ParlayParagraphBuilder object, but the public API currently doesn’t offer this.)

Start by calling parlay_init. This simply initializes some FreeType objects.

Then, register some fonts with parlay_register_font. Each font is given a name and up to four font files (for regular, italic, bold, and bold-italic). The fonts can be TrueType or Type 1.

Once initialized, to lay out some text, you have to initialize two structures and pass them to parlay_plain_text along with the text you want to render. The first structure is PaylayStyle, which contains style information. The second is ParlayControl, which has some options for layout control. You’ll also create a structure, ParlayRGBARawImage, to receive the image buffer output.

If you build it with MiniXML, you could call parlay_markup_text instead.

Example


#include "parlay.h"

int parlay_hello(char* font_filename) {
    ParlayRGBARawImage image;
    ParlayStyle style;
    ParlayControl ctl;

    /* "Hello, world" isn't really long enough to show paragraph layout so we
    use a slightly longer message */

    const char* message = "Hello, my name is Inigo Montoya. You killed my father. Prepare to die.";

    /* Initialize Parlay */

    if (parlay_init() != 0) {
        /* error if parlay_init() returns nonzero */
        return -1;
    }

    /* Register the given font with the name "hello" */
    /* Arguments 3, 4, and 5 to parlay_register_font allow one to
    specify filenames for the italic, bold, and bold-italic
    styles, but to keep the example simple we'll not bother. */

    if (parlay_register_font("hello",font_filename,NULL,NULL,NULL) != 0) {
        /* error if parlay_register_font() returns nonzero */
        return -1;
    }

    /* Set up the style structure */

    style.font_name = "hello";  /* same name we registered the font as */
    style.font_size = 20;       /* size is roughly the number of pixels wide for lower-case m */
    style.font_scaler = 1.0;    /* a convenience to allow common scaling of fonts; just set to 1 */
    style.font_style = PARLAY_STYLE_NORMAL;  /* don't use bold or italic */
    style.text_color[0] = 0.0;  /* red component of text color, in range from 0 to 1 */
    style.text_color[1] = 0.0;  /* green component of text color */
    style.text_color[2] = 0.0;  /* blue component of text color */
    style.text_color[3] = 1.0;  /* alpha component of text color, 1 = fully opaque */
    style.border_thickness = 0; /* no border around the glyphs */
    style.highlight = 0;        /* no highlighting */

    /* Set up the control structure */

    ctl.width = 300;            /* number of pixels wide to wrap the paragraph--use 0 for no wrapping */
    ctl.text_alignment = PARLAY_ALIGN_CENTER; /* paragraph alignment */
    ctl.collapse_whitespace = 0; /* don't collapse whitespace--this option is mainly for markup */
    ctl.cropping_strategy = PARLAY_CROP_FAILSAFE; /* retain all rendered pixels */

    /* It's unnecessary but good practice to clear the image structure when not in use */

    image.data = NULL;    /* will be set to point at the malloc'ed image buffer */
    image.width = 0;      /* will be set to the width of the image buffer */
    image.height = 0;     /* will be set to the height of the image buffer */
    image.x0 = 0;         /* will be set to the recommended x-location to draw the buffer */
    image.y0 = 0;         /* will be set to the recommended y-location to draw the buffer */

    /* Now call parlay_plain_text */

    if (parlay_plain_text(message,&style,&ctl,&image) != 0) {
        /* error if parlay_register_font() returns nonzero */
        /* notice a pattern? */
        return -1;
    }

    /* The ParlayRGBARawImage structure has been filled with the image data */
    /* For this example just print out the width and height of it */
    /* A better example would show how the image buffer is used somehow */

    printf("parlay_plain_text produced an image of size %d x %d\n",image.width,image.height);

    /* We're done with image, free the image data. */

    parlay_free_image_data(&image);

    return 0;
}

What To Do With Your Shiny New Image Buffer

I mean, it’s kind of out of the scope of this README, but for those skimming this file wondering, “Can Parlay do this?”, here are some examples of fun and cool things you can do with the image buffer output of Parlay.

  • You can use it to create OpenGL textures by passing it to glTexImage2D. (I assume you can do something similar with Direct X but I’ve never used it.)
  • You can use an image format library, such as libpng or libjpeg, to save the buffer in a standard image format.
  • You can use the image buffer to initialize a Pixmap object of some sort from a GUI Framework such as Qt or GTK, though if we’re being fair, in most cases you’d just want to use the text capabilities built into the GUI Framework for that.
  • You can do image operations (like compose, overlay, convolve, etc.) with other in-memory image buffers.
  • You can load a cute picture of a kitten or a blobfish from the Internet into memory, and then use Parlay to add a funny or sarcastic caption to it, save that combined image to a file, and upload it to a social media website such as Twitter or Linkedin.

Some of these might need a little manipulation of the image data. The data format of the buffer is the obvious one. Each pixel is four unsigned chars, in order RGBA. Each row is an array of pixels from left to right. The whole image is a an array of rows from top to bottom. Width and height are returned in the image structure.

History

I wrote Parlay for a game I was working on, The Ditty of Carmeana.

Early on in development, I realized my crude way of rendering individual letters from an alphabet texture didn’t scale up well, and looked terrible. (Even by Ditty of Carmeana standards, which, if you decide to look into the game, you will see are very very, low.) I decided my next step was to use real font rendering, and because I’m a modern, savvy programmer who mindlessly heeds the woke advice to reuse code and not reinvent the wheel, I went looking for a freeware library that could do this for me.

Perhaps I didn’t search the Internet well enough, but I could not find a library that could simply lay out a paragraph of text into a memory buffer. The only applicable library I found was Pango. Pango could do what I wanted, it just could not do what I wanted simply.

The less I say about Pango the better. (Put it this way: the two things in the world I hate most are Pango and Adolf Hitler… in that order.) I will only mention that the last straw was when it turned out to have a complete inability to specify a application font. All font selection had to go through Font-Config, which manages system fonts, and this was so baked into Pango it was like altering a law of nature to get it to use an app font.

So I reinvented the wheel.

That’s what this is. When The Ditty of Carmeana was Greenlit on Steam (so this is a while back), I decided it was worth my while to write my own paragraph layout engine, that could do what I needed it to do, lay out paragraphs to an in-memory image… simply.

Minor Software Packages

FCAP Minor Mode for Emacs

  • Language: Emacs Lisp
  • Platform: Emacs
  • Licence: Public Domain

This is a minor mode for Emacs that automatically capitalizes in Fortran 77, without needing to resort to CAPS LOCK. Also, it conveniently doesn’t capitalize inside strings and comments. I find it extremely helpful and never program in Fortran without it.

ftpupsync

  • Language: Python 2.1
  • Platform: Unix
  • Licence: Public Domain

This is a small script that can synchronize an FTP directory tree with a directory tree on the local disk. It does this by maintaining a catalog of everything it believes is on the FTP server; and updating the catalog whenever it updates the files on the server.

In this way, you can have a mirror of (for example) your website on your local disk, and whenever you make a change to the local mirror, you can run this script to update the pages on your server. It will make and remove directories as needed, and upload and remove files as needed. Only the new and changed files are uploaded. Renaming a file in the local mirror will usually result in that file being renamed on the server.

Unfortunately, it only works in one direction: independently changing a file on the server will not cause it to be downloaded to your local mirror.

I put this script on my web page because I think people will find it useful. However, it has a lot of loose ends untied. There’s no documentation; you’ll have to read the source to figure out how to use it. It won’t work on Windows as is, for it uses some Unix-specific calls, but it shouldn’t be hard to modify it so that it will. Finally, there is no built-in way to create the catalog. You’ll have to create the initial catalog yourself (maybe by modifying the script to just output a check file).

I still use this script to keep my static files up to date.

Dice3DS

  • Language: Python
  • License: BSD-style
  • Platform: Windows, Linux, Mac

Dice3DS is a set of Python modules for dealing with 3D Studio format files. I have released it under the terms of a BSD-style license.

3D Studio is a 3D graphics modeling and rendering program that saved it images in a rather simple binary file format known as 3DS format. Although 3D Studio has not released the details of the 3DS format, it has been reverse engineered by some ambitious people, and I used the information to write Dice3DS, a Python package that slices and dices 3DS files.

Dice3DS requires Python 2.6, and numpy 1.1.0. (Earlier versions of Python, going back to 2.2, might still work but are no longer officially supported.) The view3ds script additionally requires any or all of PIL, PyOpenGL 3, PyGame, and Pyglet. PIL and PyOpenGL is enough for most cases.

Examples

Here is an example of creating a 3DS file from scratch, and writing it to output. In the snippet, pointarray is a n-by-3 numpy array listing vertex coordinates, and facearray is an m-by-3 listing of point indices making up a face.


from Dice3DS import dom3ds
import numpy

def output_model(facearray,pointarray,filename):

    n = len(pointarray)
    m = len(facearray)

    # First, add a fourth column to facearray for the face flags.
    # Dice3DS pretty much ignores these flags, but they're required by
    # the 3DS format.

    padfacearray = numpy.zeros((n,4),numpy.uint32)
    padfacearray[:,:3] = facearray
    padfacearray[:,3] = 7

    # Create a smoothing group array.  When the whole model is to be
    # smooth, it is appropriate to set the array to all ones.

    smoothing = numpy.ones(m,numpy.uint32)

    # Create an N_TRI_OBJECT, which is basically a big list of
    # triangles.  This object lists the vertices, faces, smoothing
    # groups, and the transformation matrix, which is set to identity.
    #
    # Note that you can initialize a 3DS chunk in one of two ways: by
    # passing keyword arguments to its constructor, or assigning
    # attributes.

    obj = dom3ds.N_TRI_OBJECT()
    obj.points = dom3ds.POINT_ARRAY(npoints=n,array=pointarray)
    obj.faces = dom3ds.FACE_ARRAY(nfaces=m,array=padfacearray)
    obj.faces.smoothing = dom3ds.SMOOTH_GROUP(array=smoothing)
    obj.matrix = dom3ds.MESH_MATRIX(array=numpy.identity(4,numpy.float32))

    # Create a named object.  Give it the name OBJECT, and set its
    # object to the N_TRI_OBJECT created above.

    nobj = dom3ds.NAMED_OBJECT(name="OBJECT",obj=obj)

    # Now, create the stuff that appears in every (or almost every)
    # 3DS file.

    dom = dom3ds.M3DMAGIC()
    dom.version = dom3ds.M3D_VERSION(number=3)
    dom.mdata = dom3ds.MDATA()
    dom.mdata.scale = dom3ds.MASTER_SCALE(value=1.0)
    dom.mdata.objects = [ nobj ]

    # Output the 3DS file

    dom3ds.write_3ds_file(filename,dom)

Scripts

Dice3DS provides is two scripts, dump3ds and view3ds:

  • dump3ds dumps the a 3DS file to output in human-readable form.
  • view3ds is a simple 3DS model viewer.

Downloads

Dice3DS is licensed under a BSD-style license.

Version 0.13 is the most recent version, released 5 October 2010.

If you do Subversion you can get the latest updates here:

Links

Here are links to the homepages of the libraries used by Dice3DS:

Here are some links to other libraries and information about the 3DS file format:

About the name

I originally was going to call it Utility3DS or Util3DS. (Lib3DS was taken, and Py3DS is just lame, as all Py* names are). However, Utility is a boring and aesthetically unpleasing name, and didn’t sound right. (I couldn’t call it 3DSUtil because it needed to be a legal Python symbol.

So, I decided to name it Dice3DS in honor the famous cliche “It slices, it dices!” Definitely cooler and more euphonic than Util3DS.

IOCCC Flight Simulator

Be sure to visit our Facebook Page.

The IOCCC Flight Simulator was the winning entry in the 1998 International Obfuscated C Code Contest. It is a flight simulator in under 2 kilobytes of code, complete with relatively accurate 6-degree-of-freedom dynamics, loadable wireframe scenery, and a small instrument panel.

IOCCC Flight Simulator runs on Unix-like systems with X Windows. As per contest rules, it is in the public domain.

Documentation

Introduction

You have just stepped out of the real world and into the virtual. You are now sitting in the cockpit of a Piper Cherokee airplane, heading north, flying 1000 feet above ground level.

Use the keyboard to fly the airplane. The arrow keys represent the control stick. Press the Up Arrow key to push the stick forward. Press the left arrow key to move the stick left, and so on. Press Enter to re-center the stick. Use Page Up and Page Down increase and decrease the throttle, respectively. (The rudder is automatically coordinated with the turn rate, so rudder pedals are not represented.)

On your display, you will see on the bottom left corner three instruments. The first is the airspeed indicator; it tells you how fast you’re going in knots. The second is the heading indicator, or compass. 0 is north, 90 is east, 180 is south, 270 is west. The third instrument is the altimeter, which measures your height above ground level in feet.

Usage

To use, type:


cat horizon.sc pittsburgh.sc | ./banks

banks is the name of the program (a quirk of IOCCC rules, and no pun intended). horizon.sc and pittsburgh.sc are scenery files.

Features

  • Simulator models a Piper Cherokee, which is a light, single-engine, propeller-driven airplane.
  • The airplane is modeled as a six degree-of-freedom rigid body, accurately reflecting its dynamics (for normal flight conditions, at least).
  • Fly through a virtual 3-D world, while sitting at your X console.
  • Loadable scenery files.
  • Head-up display contains three instruments: a true airspeed indicator, a heading indicator (compass), and an altimeter.
  • Flight controls may be mapped to any keys at compile time by redefining the macros in the build file. Nice if your keyboard doesn’t have arrow keys.
  • Time step size can be set at compile time. This is useful to reduce flicker on network X connections. (But be careful: step sizes longer than about 0.03 seconds tend to have numerical stability problems.)
  • Airplane never stalls!
  • Airplane never runs out of fuel!

Scenery

Each of the *.sc files is a scenery file. The simulator program reads in the scenery from standard input on startup. You may input more than one scenery file, as long as there are less than 1000 total lines of input.

Here is a brief description of the scenery files:

  • horizon.sc – A horizon, nothing more. You will probably always want to input this piece of scenery.
  • mountains.sc – An alternate horizon; a little more mountainous.
  • pittsburgh.sc – Scenery of downtown Pittsburgh. The downtown area is initially located to your right.
  • bb.sc – Simple obstacle course. Try to fly over the buildings and under the bridges.
  • pyramids.sc – Fly over the tombs of the ancient Pharaohs in this (fictitious) Egyptian landscape.
  • river.sc – Follow a flowing river from the sky.

A few examples of how to input scenery:


cat horizon.sc pittsburgh.sc | ./banks
cat mountains.sc bb.sc | ./banks
cat mountains.sc river.sc pyramids.sc | ./banks

You can simulate flying through a cloud bank as well:


./banks < /dev/null

You will usually want at least a horizon, though.

The format of scenery files is simple, by the way. They’re just a list of 3-D coordinates, and the simulator simply draws line segments from point to point as listed in the scenery file. 0 0 0 is used to end a series of consecutive line segments. Note that in the coordinate system used, the third coordinate represents altitude in a negative sense: negative numbers are positive altitudes.

I’m sure you’ll be making your own scenery files very soon!!!

Alternate Build Instructions

Several options must be passed to the compiler to make the build work. The provided build file has the appropriate options set to default values. Use this section if you want to compile with different options.

To map a key to a control, you must pass an option to the compiler in the format “-Dcontrol=key”. The possible controls you can map are described in the table below:


Control  Description           Default Key
-------  --------------------- -----------
IT       Open throttle         XK_Page_Up
DT       Close throttle        XK_Page_Down
FD       Move stick forward    XK_Up
BK       Move stick back       XK_Down
LT       Move stick left       XK_Left
RT       Move stick right      XK_Right
CS       Center stick          XK_Enter

Values for the possible keys can be found in the X Windows header file <X11/keysym.h>. This file is most likely a cross-reference to another header, <X11/keysymdef.h>.

You must map all seven controls to keys at compile time, or the compilation will fail.

For example, to map Center Stick to the space-bar, the compile option would be “-DCS=XK_space”.

To set the time step size, you must pass the following option to the compiler: “-Ddt=duration”, where dt is literal, and where duration is the time in seconds you want the time step to be.

Two things to keep in mind when selecting a time step. Time steps that are too large (more than about 0.03) will cause numerical stability problems and should be avoided. Setting the time step to be smaller than your clock resolution will slow down the simulator, because the system pauses for more time than the simulator expects.

The best advice is to set time step size to your system timer resolution. Try a longer period if you’re getting too much flicker.

Screen Shots

Here we are flying towards Downtown Pittsburgh. We can see the Point, several buildings including the USX tower, and several bridges including the Smithfield Street bridge. We see three instruments near the bottom.

About the IOCCC Entry

IOCCC stands for “International Obfuscated C Code Contest.” It is an quasi-annual contest to see who can write the most unreadable, unintelligible, unmanagable, but legal C program.

In the 1998 IOCCC, My flight simulator won the “Best of Show” prize. Here is the source code to the program:


#include                                     <math.h>
#include                                   <sys/time.h>
#include                                   <X11/Xlib.h>
#include                                  <X11/keysym.h>
                                          double L ,o ,P
                                         ,_=dt,T,Z,D=1,d,
                                         s[999],E,h= 8,I,
                                         J,K,w[999],M,m,O
                                        ,n[999],j=33e-3,i=
                                        1E3,r,t, u,v ,W,S=
                                        74.5,l=221,X=7.26,
                                        a,B,A=32.2,c, F,H;
                                        int N,q, C, y,p,U;
                                       Window z; char f[52]
                                    ; GC k; main(){ Display*e=
 XOpenDisplay( 0); z=RootWindow(e,0); for (XSetForeground(e,k=XCreateGC (e,z,0,0),BlackPixel(e,0))
; scanf("%lf%lf%lf",y +n,w+y, y+s)+1; y ++); XSelectInput(e,z= XCreateSimpleWindow(e,z,0,0,400,400,
0,0,WhitePixel(e,0) ),KeyPressMask); for(XMapWindow(e,z); ; T=sin(O)){ struct timeval G={ 0,dt*1e6}
; K= cos(j); N=1e4; M+= H*_; Z=D*K; F+=_*P; r=E*K; W=cos( O); m=K*W; H=K*T; O+=D*_*F/ K+d/K*E*_; B=
sin(j); a=B*T*D-E*W; XClearWindow(e,z); t=T*E+ D*B*W; j+=d*_*D-_*F*E; P=W*E*B-T*D; for (o+=(I=D*W+E
*T*B,E*d/K *B+v+B/K*F*D)*_; p<y; ){ T=p[s]+i; E=c-p[w]; D=n[p]-L; K=D*m-B*T-H*E; if(p [n]+w[ p]+p[s
]== 0|K <fabs(W=T*r-I*E +D*P) |fabs(D=t *D+Z *T-a *E)> K)N=1e4; else{ q=W/K *4E2+2e2; C= 2E2+4e2/ K
 *D; N-1E4&& XDrawLine(e ,z,k,N ,U,q,C); N=q; U=C; } ++p; } L+=_* (X*t +P*M+m*l); T=X*X+ l*l+M *M;
  XDrawString(e,z,k ,20,380,f,17); D=v/l*15; i+=(B *l-M*r -X*Z)*_; for(; XPending(e); u *=CS!=N){
                                   XEvent z; XNextEvent(e ,&z);
                                       ++*((N=XLookupKeysym
                                         (&z.xkey,0))-IT?
                                         N-LT? UP-N?& E:&
                                         J:& u: &h); --*(
                                         DN -N? N-DT ?N==
                                         RT?&u: & W:&h:&J
                                          ); } m=15*F/l;
                                          c+=(I=M/ l,l*H
                                          +I*M+a*X)*_; H
                                          =A*r+v*X-F*l+(
                                          E=.1+X*4.9/l,t
                                          =T*m/32-I*T/24
                                           )/S; K=F*M+(
                                           h* 1e4/l-(T+
                                           E*5*T*E)/3e2
                                           )/S-X*d-B*A;
                                           a=2.63 /l*d;
                                           X+=( d*l-T/S
                                            *(.19*E +a
                                            *.64+J/1e3
                                            )-M* v +A*
                                            Z)*_; l +=
                                            K *_; W=d;
                                            sprintf(f,
                                            "%5d  %3d"
                                            "%7d",p =l
                                           /1.7,(C=9E3+
                              O*57.3)%0550,(int)i); d+=T*(.45-14/l*
                             X-a*130-J* .14)*_/125e2+F*_*v; P=(T*(47
                             *I-m* 52+E*94 *D-t*.38+u*.21*E) /1e2+W*
                             179*v)/2312; select(p=0,0,0,0,&G); v-=(
                              W*F-T*(.63*m-I*.086+m*E*19-D*25-.11*u
                               )/107e2)*_; D=cos(o); E=sin(o); } }

Note that this program will not compile out-of-the-box. It requires certain compile-time parameters. The folloing script builds it on my Linux system:


#! /bin/sh
cc banks.c -o banks -DIT=XK_Page_Up -DDT=XK_Page_Down \
        -DUP=XK_Up -DDN=XK_Down -DLT=XK_Left -DRT=XK_Right \
        -DCS=XK_Return -Ddt=0.02 -lm -lX11 -L/usr/X11R6/lib

If you want to try this program, I suggest you download the 1998 IOCCC Winners Distribution.

One of the rules of the contest was that the program could not be longer than 1536 bytes (excluding spaces, tabs, newlines, semicolons, and braces). Needless to say, cramming a flight simulator into such a small file was fairly difficult. I will say that if it weren’t for the wonderful property of orthogonal matrices, this flight simulator would not have been possible.

Sightings

  • The IOCCC Simulator appeared in a book, Calculated Bets by Steve Skiena.
  • Wikipedia has a listing of IOCCC Simluator in its IOCCC Entry.

Links

Downloads

I do not distribute this program myself. If you want it, you can download the 1998 IOCCC Winners Distribution. The distribution comes with a dozen or so other winning entries, all quite interesting programs.

Note that this is a source distribution, and you will have compile it to run it. I’ve tested it on some versions of Linux, AIX, Irix, and Sun.

IOCCC Flight Simulator source code is in the public domain; there are no copyright restrictions on it whatsoever. However, the winners distribution has been copyrighted by the IOCCC judges. See the hint files in the distribution for details.

Frontier Theme