/* Xpaint-filter */

#include <Xpaint.h>

/* 
 * The key-word "FilterProcess" is reserved for user-defined filter routines;
 * Such a filter processes an "input" image and renders an "output" image.
 * 
 * Pixels are unsigned char arrays p[0]=red, p[1]=green, p[2]=blue
 * (thus each value should be in the range 0..255)
 *
 * In the example below, cp = canvas pixel, ip = input pixel, op = output pixel
 * the procedure merges the input (region) with the underlying canvas image
 *
 * This is a sophisticated example showing the use of a popup menu by which
 * the user can enter further parameters to adjust the given filter routine.
 *
 */

#define NUM 4   /* number of user defined parameters */
static struct textPromptInfo prompts[NUM];
static double mat[3][3];
static int interp = 0;

/* 
 * An example of user defined function which performs a projective
 * transform depending on the values of f[i], i=0..NUM-1.
 */
Image * function(Image * input)
{
    Image * output;
    unsigned char *ip, *op;
    int i, k, l, x, y;
    double t[3];
      
    output = ImageNew(input->width, input->height);
	
    /* compute resulting image */
    for (y = 0; y < output->height; y++)
      for (x = 0; x < output->width; x++) {
        for (i=0; i<=2; i++)
	  t[i] = mat[i][0] + mat[i][1] * (double)x + mat[i][2] * (double)y;
        op = ImagePixel(output, x, y);
	if (interp)
	  PixelInterpolate(op, input, t[1]/t[0], t[2]/t[0]);
	else {
	  i = 0;
          k = t[1]/t[0] + 0.5;
          l = t[2]/t[0] + 0.5;	
          if (k < 0) i = 1;
          if (k >= input->width) i = 1;
          if (l < 0) i = 1;
          if (l >= input->height) i = 1; 
          if (i) {
	    i = -1;
            memcpy(op, &i, 3);	    
	  } else {
	    ip = ImagePixel(input, k, l);	  
            memcpy(op, ip, 3);
	  }
	}
      }
    return output;
}

/*
 * Fairly standard procedure. 
 */
void filter_proc(TextPromptInfo *info)
{
    Widget paint = Global.curpaint;
    int i;

    for (i=0; i<=2; i++)
      sscanf(info->prompts[i].rstr, "%lf %lf %lf",
	     &mat[i][0], &mat[i][1], &mat[i][2]);

    interp = (atoi(info->prompts[3].rstr)!=0);
    
    /* read user supplied data, and write them back to prompt strings */

    for (i=0; i<NUM; i++) {
      if (!info->prompts[i].rstr) continue;
      if (info->prompts[i].rstr != info->prompts[i].str) {
        free(info->prompts[i].str);
        info->prompts[i].str = strdup(info->prompts[i].rstr);
      }
    }

    /* convert region image by user supplied function */    
    ImageRegionProcess(paint, function);
}

void FilterProcess(Image * input, Image * output)
{
    static int step =0;

    /* Define NUM prompt strings (but only at first invocation) */
    if (step==0) {
      prompts[0].prompt = "first line a_11 a_12 a_13";
      prompts[0].str =  strdup("");
      prompts[0].rstr =  NULL;
      prompts[0].len = 48;
      prompts[1].prompt = "second line a_21 a_22 a_23";
      prompts[1].str =  strdup("");
      prompts[1].rstr =  NULL;
      prompts[1].len = 48;
      prompts[2].prompt = "third line a_31 a_32 a_33";
      prompts[2].str =  strdup("");
      prompts[2].rstr =  NULL;
      prompts[2].len = 48;
      prompts[3].prompt = "interpolation 0/1 ?";
      prompts[3].str =  strdup("0");
      prompts[3].rstr =  NULL;
      prompts[3].len = 8;
      ++step;
    }

    /* copy blindly image input into output before any further action */
    ImageCopyData(input, output);

    /* start popup with num values to adjust */
    PopupMenu("Projective transformation by matrix\n", NUM, prompts, filter_proc);
}


