Index: trunk/psLib/src/imageops/psImageConvolve.c
===================================================================
--- trunk/psLib/src/imageops/psImageConvolve.c	(revision 18956)
+++ trunk/psLib/src/imageops/psImageConvolve.c	(revision 18957)
@@ -7,6 +7,6 @@
 /// @author Eugene Magnier, IfA
 ///
-/// @version $Revision: 1.71 $ $Name: not supported by cvs2svn $
-/// @date $Date: 2008-05-24 23:01:42 $
+/// @version $Revision: 1.72 $ $Name: not supported by cvs2svn $
+/// @date $Date: 2008-08-08 18:07:30 $
 ///
 /// Copyright 2004-2007 Institute for Astronomy, University of Hawaii
@@ -30,4 +30,5 @@
 #include "psImagePixelManip.h"
 #include "psTrace.h"
+#include "psThread.h"
 
 #include "psImageConvolve.h"
@@ -757,4 +758,110 @@
 
 
+// Convolve mask columns
+static bool imageConvolveMaskColumns(psImage *target, // Output, convolved image
+                                     const psImage *input, // Input image
+                                     int start, int stop, // Range of rows
+                                     psMaskType maskVal, // Value to mask; NOTE subtle difference!
+                                     int xMin, int xMax // Range in x for kernel
+                                     )
+{
+    // Dereference mask images
+    psMaskType **inputData = input->data.PS_TYPE_MASK_DATA;
+    psMaskType **targetData = target->data.PS_TYPE_MASK_DATA;
+
+    int numCols = input->numCols;       // Number of columns
+
+    for (int y = start; y < stop; y++) {
+        int min = 0, max = 0;           // Minimum and maximum points to mask
+        bool masking = false;           // Currently masking?
+        for (int x = 0; x < numCols; x++) {
+            if (inputData[y][x] & maskVal) {
+                if (!masking) {
+                    masking = true;
+                    min = x + xMin;
+                    max = x + xMax;
+                } else {
+                    max++;
+                }
+            } else if (masking) {
+                // Do the masking
+                masking = false;
+                min = PS_MAX(0, min);
+                max = PS_MIN(numCols - 1, max);
+                memset(&targetData[y][min], 0xff, (max - min + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_MASK));
+            }
+        }
+        if (masking) {
+            // Mask from the minimum to the end of the row
+            min = PS_MAX(0, min);
+            memset(&targetData[y][min], 0xff, (numCols - min) * PSELEMTYPE_SIZEOF(PS_TYPE_MASK));
+        }
+    }
+    return true;
+}
+
+static bool imageConvolveMaskRows(psImage *target, // Output, convolved image
+                                     const psImage *input, // Input image
+                                     int start, int stop, // Range of rows
+                                     psMaskType setVal, // Value to set; NOTE subtle difference!
+                                     int yMin, int yMax // Range in y for kernel
+                                     )
+{
+    // Dereference mask images
+    psMaskType **inputData = input->data.PS_TYPE_MASK_DATA;
+    psMaskType **targetData = target->data.PS_TYPE_MASK_DATA;
+
+    int numRows = input->numRows;       // Number of rows
+
+    for (int x = start; x < stop; x++) {
+        int min = 0, max = 0;           // Minimum and maximum points to mask
+        bool masking = false;           // Currently masking?
+        for (int y = 0; y < numRows; y++) {
+            if (inputData[y][x]) {
+                if (!masking) {
+                    masking = true;
+                    min = y + yMin;
+                    max = y + yMax;
+                } else {
+                    max++;
+                }
+            } else if (masking) {
+                // Do the masking
+                masking = false;
+                min = PS_MAX(0, min);
+                max = PS_MIN(numRows - 1, max);
+                for (int i = min; i <= max; i++) {
+                    targetData[i][x] |= setVal;
+                }
+            }
+        }
+        if (masking) {
+            // Mask from the minimum to the end of the column
+            for (int i = PS_MAX(0, min); i < numRows; i++) {
+                targetData[i][x] |= setVal;
+            }
+        }
+    }
+    return true;
+}
+
+static bool imageConvolveMaskThread(const psThreadJob *job)
+{
+    PS_ASSERT_THREAD_JOB_NON_NULL(job, false);
+
+    psArray *args = job->args;          // Arguments for job
+
+    psImage *target = args->data[0];       // Output mask image
+    const psImage *input = args->data[1];// Input mask image
+    int start = PS_SCALAR_VALUE(args->data[2], S32); // Row/col to start at
+    int stop = PS_SCALAR_VALUE(args->data[3], S32); // Row/col to stop at
+    psMaskType maskVal = PS_SCALAR_VALUE(args->data[4], U8); // Value to mask/set
+    int kernelMin = PS_SCALAR_VALUE(args->data[5], S32); // Minimum range for kernel
+    int kernelMax = PS_SCALAR_VALUE(args->data[6], S32); // Maximum range for kernel
+    bool row = PS_SCALAR_VALUE(args->data[7], U8); // Do row (true) or column (false)?
+
+    return row ? imageConvolveMaskRows(target, input, start, stop, maskVal, kernelMin, kernelMax) :
+        imageConvolveMaskColumns(target, input, start, stop, maskVal, kernelMin, kernelMax);
+}
 
 
@@ -792,4 +899,14 @@
     }
 
+    static bool threadsInit = false;    // Threads initialised?
+    int numThreads = psThreadPoolSize();// Number of threads
+    if (numThreads > 0 && !threadsInit) {
+        psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_CONVOLVE_MASK", 8);
+        task->function = &imageConvolveMaskThread;
+        psThreadTaskAdd(task);
+        psFree(task);
+        threadsInit = true;
+    }
+
     int numRows = mask->numRows;        // Number of rows
     int numCols = mask->numCols;        // Number of columns
@@ -805,10 +922,84 @@
     psImageInit(conv, 0);
 
-    // Dereference mask images
-    psMaskType **maskData = mask->data.PS_TYPE_MASK_DATA;
-    psMaskType **convData = conv->data.PS_TYPE_MASK_DATA;
-    psMaskType **outData = out->data.PS_TYPE_MASK_DATA;
-
     // Since we're just masking everything inside a square, it's separable
+
+    // Rows
+    if (numThreads > 0) {
+        float cols = (float)numCols / (float)numThreads; // Number of cols to do at once
+        for (int i = 0; i < numThreads; i++) {
+            int start = i * cols;       // Starting colunms
+            int stop = (i + 1) * cols;  // Stopping columns
+
+            psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_CONVOLVE_MASK");
+            psArrayAdd(job->args, 1, conv);
+            psArrayAdd(job->args, 1, (psImage*)mask); // Casting away const to put on arguments
+            PS_ARRAY_ADD_SCALAR(job->args, start, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, stop, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_MASK);
+            PS_ARRAY_ADD_SCALAR(job->args, xMin, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, xMax, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, 0x00, PS_TYPE_U8);
+            if (!psThreadJobAddPending(job)) {
+                psFree(job);
+                psFree(conv);
+                psFree(out);
+                return NULL;
+            }
+            psFree(job);
+        }
+    } else if (!imageConvolveMaskColumns(conv, mask, 0, numRows, maskVal, xMin, xMax)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to convolve mask columns.");
+        psFree(conv);
+        psFree(out);
+        return NULL;
+    }
+
+    if (!psThreadPoolWait(true)) {
+        psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
+        psFree(conv);
+        psFree(out);
+        return NULL;
+    }
+
+    // Columns
+    if (numThreads > 0) {
+        float cols = (float)numCols / (float)numThreads; // Number of columns to do at once
+        for (int i = 0; i < numThreads; i++) {
+            int start = i * cols;       // Starting column
+            int stop = (i + 1) * cols;  // Stopping column
+
+            psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_CONVOLVE_MASK");
+            psArrayAdd(job->args, 1, conv);
+            psArrayAdd(job->args, 1, out);
+            PS_ARRAY_ADD_SCALAR(job->args, start, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, stop, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, setVal, PS_TYPE_MASK);
+            PS_ARRAY_ADD_SCALAR(job->args, xMin, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, xMax, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, 0xff, PS_TYPE_U8);
+            if (!psThreadJobAddPending(job)) {
+                psFree(job);
+                psFree(conv);
+                psFree(out);
+                return NULL;
+            }
+            psFree(job);
+        }
+    } else if (!imageConvolveMaskRows(out, conv, 0, numCols, setVal, yMin, yMax)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to convolve mask columns.");
+        psFree(conv);
+        psFree(out);
+        return NULL;
+    }
+
+    if (!psThreadPoolWait(true)) {
+        psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
+        psFree(conv);
+        psFree(out);
+        return NULL;
+    }
+
+
+#if 0
     for (int y = 0; y < numRows; y++) {
         int min = 0, max = 0;           // Minimum and maximum points to mask
@@ -866,4 +1057,5 @@
         }
     }
+#endif
 
     psFree(conv);
@@ -871,2 +1063,3 @@
     return out;
 }
+
