CFDG Introduction

Context Free (and the command-line tool cfdg) is a digital art program that takes a description of an image and generates the image (as a bitmap, vector image, or movie). The description is in the form of a context free grammar and is called a cfdg file (aka context free design grammar). The typical use of a context free grammar is to analyze a sentence of symbols to see if they can reduce to some root symbol. Context Free turns this around by starting with a root symbol/shape (called the startshape) and using the grammar rules to elaborate this into a sentence of symbols/shapes (squares, circles, triangles, fills, or user-defined).

Version 2 of Context Free
This page describes the current version of Context Free. But you will encounter cfdg files that look different, but still execute in Context Free. These files are from Context Free 2.2 and earlier and have a different syntax. The Version 2 Syntax page describes how to understand these older files and provides translation tools.

= Shape Rules = A shape rule describes how to draw a shape in terms of other shapes, called shape replacements. The replacement shapes can be recursive invocations to the same shape, invocations of other shapes that have rules, or primitive shapes. When a rule is executed the end result is some number of shapes that require further execution and some number of primitive shapes that are placed in the shape sentence. Here is some example code by Chris Coyne:

Shape blah is defined in terms of four 'blah2' shapes. Shape blah2 is recursively defined and draws a square primitive shape on each iteration.

= Shape Adjustments = In the above example there was some text inside square brackets following each shape replacement. These are called shape adjustments. When a shape is executed it has some information associated with it, called its world state: its geometry, its color, its z-position, and its lifetime (used in animation). This information passes to the shape replacements, but it is modified by the shape adjustment. Let's break down flip 90 changes the geometry by reflecting the blah2 shape across the y-axis (90&deg;). alpha -1 changes the color to transparent. x 5 adjusts the geometry by shifting right 5 units. And b 1 adjusts the color to full brightness.

The geometry is stored as an affine transform matrix and all geometric adjustments are affine transformations. Color is stored as hue, saturation, brightness, and alpha. Color adjustments change one of these four components. Z state is stored as z position and z scale. Lifetime is stored as birth and death time and time scale.

= StartShape = The startshape directive tells Context Free the root shape for the design. If the shape takes parameters then they must be specified in the startshape directive. The shape is initialized with the default shape state: opaque black (h/s/b/a = 0/0/0/1) and identity transforms for geometry, z, and lifetime. You have the option of putting a shape adjustment after the shape name in the startshape directive. If there is a shape adjustment then the default state is adjusted with it before executing the shape.

= Expressions = Anywhere that you can put a number, you can put a numeric expression. The only exception is rule weights, which must be a numeric constant. Inside shape adjustments you can only use a subset of the expressions, called simple expressions.

Expressions support your standard +-*/ operators, parentheses, functions, comparison operators, boolean operators, and random operators.

Variables
Variables can be declared anywhere outside of shapes or inside of shapes. Global variables are computed at the start of the cfdg execution and can be referenced anywhere following their declaration. Variables local to a shape (or path) are computed each time the shape is executed, so they can be random or depend on shape parameters. If you want to have a global variable that is recomputed each time it is referenced then declare a user function with no arguments instead. Variables cannot be modified. In this code The second count declaration does not modify the first count variable. Instead it declares a new count variable that renders the first one invisible. If the first count variable was global and the second count variable was local then the global count would be invisible until the local count went out of scope. Note that the scope of the second count variable begins after the count - 1 expression, which means that the count in the count - 1 expression refers to the first count variable.

User Functions
In addition to the predefined functions you can define your own. They can simply be interesting functions that we forgot: or they can be complicated, recursive, functional programming:

= Paths = Path declaration create new primitive shapes. The contents of a path declaration are a series of path operations (line segments, arcs, and bezier curves) and drawing commands (stroke or fill a path).

= Control Structures = Shape rules and paths can have control structures that affect how the shape replacements or path elements are executed. These control structures are loops, if statements, switch statements, transform statements, and clone statements.

Loops
In this path the LINETO path operation is executed 6 times in a loop. The shape adjustment following the 6 is called the loop adjustment. The world state for the loop body is adjusted with the loop adjustment following each iteration of the loop. So the first iteration of the loop the LINETO is executed in the path world state. The second iteration is with the path world state rotated by 102.857&deg;. The third iteration is with the path world state rotated by 205.714&deg;, and so on.

If Statements
An if statement makes the execution of a block of shape replacements or path elements dependent on whether an expression is true (&ne;0) or false (=0). In this path the center of the flower is filled only if the incoming fill parameter is non-zero. If statements can also have an else clause that is only executed if the if condition is false.

Switch Statements
A switch statement evaluates a selector expression and then picks one of several blocks of shape replacements or path elements to execute based on the selector value. The selector value is rounded down to the next integer before the case block is selected. The case block indices are constant expressions that are also rounded down to the next integer.

Transform Statements
A transform statement takes a shape adjustment and executes a block of shape replacements or path elements with a world state that has been adjusted by it.

Clone Statements
A clone statement behaves just like a transform statement except that the replacement shapes all look the same, even if they are random. This violates context-free purity, so you must set CF::Impure.

= Shape/Path Parameters = In addition to the world state that a parent shape sends to child shape in a shape replacement it can also send parameters. These parameters can be numbers, shape adjustments, or shape specifications. A shape specification for shape curve includes two numeric parameters, that are bound to the variables shrink and turn when curve is executed.

= Importing CFDG Files = A cfdg file can insert the contents of another cfdg file using an import directive. The shapes, paths, variables, and user functions declared in the imported cfdg file are available following the import directive. They can also be inserted in a separate namespace if there are naming conflicts between the imported file and the importing file.

= Configuring Context Free/cfdg = Context Free's behavior can be changed by setting special configuration variables in the CF:: namespace. Most of these are fairly obscure except for the four below.

Background Color
The default background color is opaque white (hue = 0, sat = 0, b = 1, a = 1). Assigning a shape adjustment to CF::Background will change the background color accordingly.

Tiling and Symmetry
Tiled rendering (and frieze rendering) is disabled by default, but is enabled and configured by assigning a shape adjustment to CF::Tile.

Symmetry operations are enabled and configured by assigning a list of symmetry specifications to CF::Symmetry.

Size
Dynamic sizing of the canvas is disabled by assigning a shape adjustment to CF::Size. The logical size and position of the canvas is set by the adjustment.