1. Changes

1.1 The tan(x) function now generates correct in-line code for real

arguments. The valid domain for tan(real) is [-2^63, +2^63].

If you need to compute tan(x) for values outside this domain,

use the ftan(x) function, which calls the C run-time library

version of tan().

1.2 Run-time exception handling/reporting has been enhanced to include

additional information about the environment at the time the

exception occurred, including optional disassembly of the X86

machine code at the exception site.

1.3 By default, src(x,y,z) now edge-replicates the alpha channel for

values of x and y lying outside the bounds of the input image or

selection. (Previously, src() edge-replicated all channels

*except* the alpha channel; src() returned 0 for the alpha channel

for coordinates outside the image/selection.)

1.4 FM now treats a non-breaking space character (0xA0) as white space.

This allows cut-and-paste of FM code examples from Internet Explorer

to work correctly.

1.5 When re-invoking FM, the FM dialog box is now made visible *before*

re-running the filter algorithm. (Previously, if the filter algorithm

was very slow, the user would be presented with a long hourglass

wait before the dialog box appeared, which could be confusing and


2. Bug Fixes

2.1 An obscure bug that could sometimes cause GPF's within R:/G:/B:/A:

channel code has been fixed.

2.2 A bug in the updateProgress() processing within the default

ForEveryRow handler, which could result in an incorrect progress bar

display when the preview image was clipped to fit the proxy window,

has been fixed.

2.3 A bug that sometimes caused an incorrect "while looking for <token>"

display in the FM syntax error message has been fixed. (Note, however,

that there are still some other problems with the syntax error message

processing that can also result in incorrect tokens being displayed.)

3. New Features

3.1 The testAbort() function now checks for the ESC key during proxy

preview processing as well as during final image filtering. If

the user presses ESC during proxy filter processing, testAbort()

will return a non-zero value. (Note that the updateProgress()

and doForEveryRow() functions also implicitly call testAbort() and

will return non-zero if the user presses ESC.)

3.2 The testAbort() function now checks for the PAUSE key during proxy

preview processing. If the user presses PAUSE during proxy filter

processing, the filter will pause and a message box will be displayed

to ask whether the user wishes to continue. Choosing YES causes

filter processing to resume. Choosing NO causes testAbort() or

updateProgress() or doForEveryRow() to return a non-zero value,

which allows the filter code to gracefully terminate the filter.

3.3 A new function abort() has been added, which causes filter processing

to stop immediately. The most common use of abort() is to abort

filter processing when testAbort() or updateProgress() or doForEveryRow()

returns a non-zero value:

if (testAbort()) {

// User requested abort...

<do any necessary cleanup>



3.4 A new function updatePreview(n) causes the proxy preview to be

immediately updated with the current contents of the output image.

This is useful for animating iterative algorithms in the preview

window. ('n' is the ID of the proxy preview control to be updated.

At present, FM supports only one proxy preview, so 'n' is ignored.)

3.5 A new function sleep(msec) causes filter processing to pause for

approximately 'msec' milliseconds before resuming. This is useful

for controlling the rate of preview display updates when animating

iterative algorithms.

3.6 To facilitate coding of iterative algorithms, a second tile buffer

(t2buf) has been added. 't2buf' is similar to 'tbuf' and is

read/written by the new functions t2get(x,y,z) and t2set(x,y,z,val),

which are analogous to the tget/tset functions used to access tbuf.

3.7 Again to facilitate coding of iterative algorithms, a new function

pget(x,y,z) has been added as a companion to the pset(x,y,z,val)

function. pget(x,y,z) returns the value of the pixel in the output

image tile at coordinates (x,y) for channel z. By default, pget()

edge-replicates pixel values for coordinates lying outside the

bounds of the output image tile. Note that pget/pset is analogous to

tget/tset and t2get/t2set.

3.8 To facilitate animation of "classic" Filter Factory *.8bf modules,

a new function doForEveryRow() has been added. This function can

be called in a ForEveryTile handler to directly drive the ForEveryRow

handling (and thence the ForEveryPixel handling). Since the Filter

Factory-style R:/G:/B:/A: handlers are driven directly from the default

ForEveryPixel handler, this means that you can cause execution of the

R:/G:/B:/A: handlers across the entire current tile by each call to

doForEveryRow() from within your ForEveryTile handler. Thus, to

animate a classic FF filter, set the relevant control values within

your ForEveryTile handler; then call doForEveryRow() to run the

classic filter; then call updatePreview() to display the results

in the proxy preview window. Finally, re-adjust the control values

and repeat to perform the next step in the animation. doForEveryRow()

will return a non-zero value if the user presses ESC (or PAUSE followed

by NO); checking this value allows the ForEveryTile handler to perform

any necessary cleanup action before calling abort() to terminate the

filter processing.

3.9 To aid in producing high-performance filters (such as blurs) based on

separable convolution kernels, two built-in functions for computing

1-D convolutions have been added:

val = cnvX(k, off, d, pGetf, x, y, z);

val = cnvY(k, off, d, pGetf, x, y, z);


'k' is the "radius" of the kernel and must be >= 0.

'off' is the starting index within the anonymous array of put/get

cells where the kernel coefficients are stored. The number of

coefficients is n=k*2+1, where 'k' is the kernel radius.

'd' is the denominator by which the convolution sum will be divided,

and must be non-zero.

'pGetf' identifies the FM built-in function that will be called to

fetch values from an image buffer at the designated coordinates,

and must be 'src', 'tget', 't2get', or 'pget'.

'x' is the x-coordinate at which the (center of the) kernel is to be


'y' is the y-coordinate at which the (center of the) kernel is to be


'z' is the channel number to which the kernel is to be applied.

'val' is the integer result obtained by summing the products of the

n kernel coefficients with n image pixels in the X or Y direction,

and dividing the sum by 'd'.

cnvX() computes the 1-D convolution kernel in the X direction, while cnvY()

computes the 1-D convolution kernel in the Y direction. I.e., cnvX()

convolves pixels at coordinates:

(x-k,y), (x-k+1,y), ... (x-1,y), (x,y), (x+1,y), ... (x+k-1,y), (x+k,y);

while cnvY() applies the kernel to pixels at coordinates:

(x,y-k), (x,y-k+1), ... (x,y-1), (x,y), (x,y+1), ... (x,y+k-1), (x,y+k).