GridFlow 0.8.1 - Reference Manual: Architecture

       

Numbers

Grid Literals

Grid Protocol

Picture Protocol

Numeric Operators

Synchronisation

Bridges



Numbers

High-performance computation requires precise and quite peculiar definitions of numbers and their representation.

Inside most programs, numbers are written down as strings of bits. A bit is either zero or one. Just like the decimal system uses units, tens, hundreds, the binary system uses units, twos, fours, eights, sixteens, and so on, doubling every time.

One notation, called integer allows for only integer values to be written (no fractions). when it is unsigned, no negative values may be written. when it is signed, one bit indicates whether the number is positive or negative. Integer storage is usually fixed-size, so you have bounds on the size of numbers, and if a result is too big it "wraps around", truncating the biggest bits.

Another notation, called floating point (or float) stores numbers using a fixed number of significant digits, and a scale factor that allows for huge numbers and tiny fractions at once. Note that 1/3 has periodic digits, but even 0.1 has periodic digits, in binary coding; so expect some slight roundings; the precision offered should be sufficient for most purposes. Make sure the errors of rounding don't accumulate, though.

This little program of mine prints 1/3 in base 2 (only digits after the period): ruby -e 'x=1/3.0;for i in 0..52 do x*=2;y=x.floor;print y;x-=y end;puts'

In GridFlow, there are six kinds of numbers:

namealiasesrangesize (bytes)precisiondescription
uint8u8 b0..25511 unsigned 8-bit integer. this is the usual size of numbers taken from files and cameras, and written to files and to windows. (however this gets converted to int32 unless otherwise specified.)
int16i16 s±215 = -32768..3276721...
int32i32 i±231 = -2147483648..214748364741 signed 32-bit integer. this is used for most computations.
int64i64 l±26381...
float32f32 f±10±38423 bits = 0.000012% (about 7 digits)...
float64f64 d±10±308852 bits (about 15 digits)...
 

Grid Literals

In every grid-accepting inlet, a list may be sent instead; if it consists only of integers, it will be converted to a one-dimensional grid. Else it may contain a single "#" sign and integers on both sides of it, where the ones to the left of it are fed as arguments to an imaginary [#redim] object and the one to the right of it are fed through that [#redim].

In every grid-accepting inlet, an integer or float may also be sent; it will be converted to a zero-dimensional grid (a scalar).

 

Grid Protocol

a grid has an associated number type that defines what are the possible values for its elements (and how much space it takes). the default is int32.

a single-dimensional grid of 3 elements (a triplet) is called dim(3). a three-dimensional grid of 240 rows of 320 columns of triplets is called dim(240,320,3).

There is a sequence in which elements of a Grid are stored and transmitted. Dimension 0 is called "first" and dimension N-1 is called "last". They are called so because if you select a position in the first dimension of a grid, the selected part is of the same shape minus the first dimension; so in dim(240,320,3) if you select row 51 (or whichever valid row number), you get a dim(320,3). if you select a subpart two more times you get to a single number.

At each such level, elements are sent/stored in their numeric order, and are numbered using natural numbers starting at 0. This ordering usually does not matter, but sometimes it does. Most notably, [#import], [#export] and [#redim] care about it.

On the other hand, order of dimensions usually does matter; this is what distinguishes rows from columns and channels, for example. Most objects care about the distinction.

A grid with only 1 element in a given dimension is different from one lacking that dimension; it won't have the same meaning. You can use this property to your advantage sometimes.

Zero-dimensional grids exist. They are called dim(). They can only contain a single number.

 

Picture Protocol

This section is useful if you want to know what a picture is in terms of a grid.

A picture is a three-dimensional Grid:

  • 0 : rows
  • 1 : columns
  • 2 : channels

Channels for the RGB color model are:

  • 0 : red
  • 1 : green
  • 2 : blue

Because Grids are made of 32-bit integers, a three-channel picture uses 96 bpp (bits per pixel), and have to be downscaled to 24 bpp (or 16 bpp) for display. That huge amount of slack is there because when you create your own effects you often have intermediate results that need to be of higher precision than a normal picture. Especially, results of multiplications are big and should not overflow before you divide them back to normal; and similarly, you can have negative values all over, as long as you take care of them before they get to the display.

In the final conversion, high bits are just ignored. This means: black is 0, maximum is 255, and values wrap like with % 256. If you want to clip them, you may use [# max 0] and [# min 255] objects.

 

Numeric Operators

In the following table, A is the value entered to the left, and B is the value entered to the right.

Angles are in hundredths of degrees. This means a full circle (two pi radians) is 36000. You convert from degrees to our angles by multiplying by 100. You convert from radians to our angles by multiplying by 18000/pi.

Hyperbolic functions (tanh) work with our angles too, so the same conversions apply.

namedescriptionmeaning in pixel context (pictures, palettes)meaning in spatial context (indexmaps, polygons)
ignore A no effectno effect
put B replace byreplace by
+ A + B brightness, crossfademove, morph
- A - B brightness, motion detectionmove, motion detection
inv+ B - A negate then contrast180 degree rotate then move
* A * B contrastzoom out
/ A / B, rounded towards zero contrastzoom in
div A / B, rounded downwards contrastzoom in
inv* B / A, rounded towards zero ----
swapdiv B / A, rounded downwards ----
% A % B, modulo (goes with div) --tile
swap% B % A, modulo (goes with div) ----
rem A % B, remainder (goes with /) ----
swaprem B % A, remainder (goes with /) ----
gcd greatest common divisor----
lcm least common multiple----
| A or B, bitwise bright munchiesbottomright munchies
^ A xor B, bitwise symmetric munchies (fractal checkers)symmetric munchies (fractal checkers)
& A and B, bitwise dark munchiestopleft munchies
<< A * (2**(B % 32)), which is left-shifting like *like *
>> A / (2**(B % 32)), which is right-shifting like /,divlike /,div
|| if A is zero then B else A ----
&& if A is zero then zero else B----
min the lowest value in A,B clippingclipping (of individual points)
max the highest value in A,B clippingclipping (of individual points)
cmp -1 when A<B; 0 when A=B; 1 when A>B. ----
== is A equal to B ? 1=true, 0=false ----
!= is A not equal to B ? ----
> is A greater than B ? ----
<= is A not greater than B ? ----
< is A less than B ? ----
>=is A not less than B ? ----
sin* B * sin(A) --waves, rotations
cos* B * cos(A) --waves, rotations
atan arctan(A/B) --find angle to origin (part of polar transform)
tanh* B * tanh(A) smooth clippingsmooth clipping (of individual points), neural sigmoid, fuzzy logic
log* B * log(A) (in base e) ----
gamma floor(pow(a/256.0,256.0/b)*256.0) gamma correction--
** A**B, that is, A raised to power B gamma correction--
abs- absolute value of (A-B) ----
rand randomly produces a non-negative number below A ----
sqrt square root of A, rounded downwards ----
sq- (A-B) times (A-B) ----
clip+ like A+B but overflow causes clipping instead of wrapping around (coming soon) ----
clip- like A-B but overflow causes clipping instead of wrapping around (coming soon) ----
avg (A+B)/2 ----
hypot square root of (A*A+B*B) ----
erf* integral of e^(-x*x) dx ... (coming soon; what ought to be the scaling factor?) ----
 

Synchronisation

In GridFlow you cannot send two grids in different inlets at the same time. You have to use [#finished] together with (possibly) [fork] and [#store], which can be cumbersome. If you don't do this, the result is undefined behaviour (or crash!).

In GridFlow 0.7.1 this is beginning to change. [#store] and # now allow right-inlet grids to be buffered if an operation is occuring on left inlet. This should make many circuits simpler.

(more to come)

 

Bridges

Starting with version 0.6, GridFlow is Ruby-centric instead of jMax-centric. jMax support has been added back as a Bridge.

Bridges, for the most part, plug into the FObject class, which is the common root of most of GridFlow's classes. Under the current design, the bridge is compiled separately, and is directly loaded by the host software; then the bridge starts Ruby and makes it load the main GridFlow; then the bridge hooks with the main part.

 

GridFlow 0.8.1 Documentation
Copyright © 2001,2002,2003,2004,2005,2006 by Mathieu Bouchard matju@artengine.ca