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). |