/* 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 coeff[4];
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 p, q, t, u;
      
    output = ImageNew(input->width, input->height);
	
    /* compute resulting image */
    for (y = 0; y < output->height; y++)
      for (x = 0; x < output->width; x++) {
	p = (double)x - coeff[0];
	q = (double)y - coeff[1];	
        t = coeff[0] + coeff[2] * p + coeff[3] * q;
        u = coeff[1] - coeff[3] * p + coeff[2] * q;	
        op = ImagePixel(output, x, y);
	if (interp)
	  PixelInterpolate(op, input, t, u);
	else {
	  i = 0;
          k = t + 0.5;
          l = u + 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;
    double a, t;
    
    sscanf(info->prompts[0].rstr, "%lf,%lf", &coeff[0], &coeff[1]);
    a = atof(info->prompts[1].rstr);
    if (a==0) return;
    a = 1/a;
    t = atof(info->prompts[2].rstr) * M_PI / 180.0;
    coeff[2] = a * cos(t);
    coeff[3] = a * sin(t);
    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 = "center x0,y0";
      prompts[0].str =  strdup("400,300");
      prompts[0].rstr =  NULL;
      prompts[0].len = 30;
      prompts[1].prompt = "homothety factor";
      prompts[1].str =  strdup("");
      prompts[1].rstr =  NULL;
      prompts[1].len = 30;
      prompts[2].prompt = "angle";
      prompts[2].str =  strdup("");
      prompts[2].rstr =  NULL;
      prompts[2].len = 30;
      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);
}


