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
disconcerting.)
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>
abort();
}
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
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);
where:
'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
applied.
'y' is the y-coordinate at which the (center of the) kernel is to be
applied.
'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).