/* 
 * This plugin takes 1 strip as input and cartoonify's it.
 *  Based off of: Dries Pruimboom (dries@irssystems.nl)'s standalone app...
 * You can find his code here: http://members.lycos.nl/dpruimboom/
 * Author: SirDude
 * Email: mein@cs.umn.edu 
 * Website: http://www.cs.umn.edu/~mein/blender
 * License: GNU
 * Date: Fri Jan 25 16:09:30 CST 2002
 */

#include <math.h>
#include "plugin.h"

char name[24]= "cartoon";	

/* structure for buttons, 
 *  butcode      name           default  min  max  comment
 */
VarStruct varstr[]= {
   { LABEL,	"In: 1 strip", 0.0, 0.0, 0.0, ""}, 
   { NUM|INT,	"triplevel", 150.0, 1.0, 255.0, "Threshold for Blackness"}, 
   { NUM|INT,	"diffspace", 1.0, 1.0, 255.0, "Pixel distance away to check"}, 
   { TOG|INT,	"Flatten", 1.0, 0.0, 1.0, "Flatten the colors"}, 
   { TOG|INT,	"Boost", 1.0, 0.0, 1.0, "Boost the colors"}, 
};

/* The cast struct is for input in the main doit function
   Varstr and Cast must have the same variables in the same order */ 
typedef struct Cast {
	int dummy, triplevel,diffspace,flatten,boost;
} Cast;


/* cfra: the current frame */
float cfra;

void plugin_seq_doit(Cast *, float, float, int, int, 
   ImBuf *, ImBuf *, ImBuf *, ImBuf *);

int plugin_seq_getversion(void) { return B_PLUGIN_VERSION; }
void plugin_but_changed(int but) { }
void plugin_init() { }

void plugin_getinfo(PluginInfo *info) {
   info->name= name;
   info->nvars= sizeof(varstr)/sizeof(VarStruct);
   info->cfra= &cfra;

   info->varstr= varstr;

   info->init= plugin_init;
   info->seq_doit= (SeqDoit) plugin_seq_doit;
   info->callback= plugin_but_changed;
}

void FlattenColor(char *c) {
   c[0] = 40*(c[0]/40);
   c[1] = 40*(c[1]/40);
   c[2] = 40*(c[2]/40);
}

void ColorBoost(char *c) {
   int max=0;
   
   /*   Find biggest of r,g and b */
   if (c[0] > max) max = c[0];
   if (c[1] > max) max = c[1];
   if (c[2] > max) max = c[2];

   /*  make biggest component 100% (255) */
   if (max!=0) {
       c[0] = (c[0]*255)/max;
       c[1] = (c[1]*255)/max;
       c[2] = (c[2]*255)/max;
   }
}

int geterror(char *c1, char *c2) {
   int i,x,value = 0;
 
   for (i=0;i<4;i++) {
      x=c1[i]-c2[i];
      value = value + x*x;
   }
   return value;
}

long GetMaxContrast(char *in, int x, int y, int xo, int yo, Cast *cast, 
   int dest) {
   char c1[4], c2[4];
   long error,max=0;
   int i;
   
   /*
    *  Calculate first error (horizontal)
    */
   if ((x>= cast->diffspace) && (x <= xo - cast->diffspace)) {
      for(i=0;i<4;i++) {
         c1[i] = in[(x-cast->diffspace + y * xo)*4 + i];
         c2[i]= in[(x+cast->diffspace + y * xo)*4 + i];
      }

      if (cast->flatten) {
         FlattenColor(c1);
         FlattenColor(c2);
      }
      if (cast->boost) {
         ColorBoost(c1);
         ColorBoost(c2);
      }

      error=geterror(c1,c2);
      if (error>max) max=error;
   }

   /*
    *  Calculate second error (vertical)
    */
   if ((y>= cast->diffspace) && (y <= yo - cast->diffspace)) {
      for(i=0;i<4;i++) {
         c1[i]= in[(x + (y - cast->diffspace) * xo)*4 + i];
         c2[i]= in[(x + (y + cast->diffspace) * xo)*4 + i];
      }

      if (cast->flatten) {
         FlattenColor(c1);
         FlattenColor(c2);
      }
      if (cast->boost) {
         ColorBoost(c1);
         ColorBoost(c2);
      }

      error=geterror(c1,c2);
      if (error>max) max=error;
   }
   
   /*
    *  Calculate third error (upperleft-lowerright)
    */
   if ((x>= cast->diffspace) && (y <= yo - cast->diffspace) &&
       (y>= cast->diffspace) && (x <= xo - cast->diffspace)) {
      for(i=0;i<4;i++) {
         c1[i]= in[(x - cast->diffspace + (y - cast->diffspace) * xo)*4 + i];
         c2[i]= in[(x + cast->diffspace + (y + cast->diffspace) * xo)*4 + i];
      }

      if (cast->flatten) {
         FlattenColor(c1);
         FlattenColor(c2);
      }
      if (cast->boost) {
         ColorBoost(c1);
         ColorBoost(c2);
      }

      error=geterror(c1,c2);
      if (error>max) max=error;
   }

   /*
    *  Calculate fourth error (lowerleft-upperright)
    */
   if ((x>= cast->diffspace) && (y <= yo - cast->diffspace) &&
       (y>= cast->diffspace) && (x <= xo - cast->diffspace)) {
      for(i=0;i<4;i++) {
         c1[i]= in[(x + cast->diffspace + (y - cast->diffspace) * xo)*4 + i];
         c2[i]= in[(x - cast->diffspace + (y + cast->diffspace) * xo)*4 + i];
      }

      if (cast->flatten) {
         FlattenColor(c1);
         FlattenColor(c2);
      }
      if (cast->boost) {
         ColorBoost(c1);
         ColorBoost(c2);
      }

      error=geterror(c1,c2);
      if (error>max) max=error;
   }
   
   return(max);
}

void plugin_seq_doit(Cast *cast, float facf0, float facf1, int xo, int yo, 
	ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *outbuf, ImBuf *use) {
   char *in, *out;
   int x, y, dest, i;

   in = (char *)ibuf1->rect;
   out = (char *)outbuf->rect;
   
   for(y=0;y<yo;y++) {
      for(x=0;x<xo;x++) {
         dest = (x + y * xo)*4;
	 if (GetMaxContrast(in, x, y, xo, yo, cast, dest) > cast->triplevel) {
	    /* Set output pixel to black */
            for (i=0;i<4;i++) out[dest + i] =0;
         } else {
            for (i=0;i<4;i++) out[dest + i] =in[dest +i];
            if (cast->flatten) FlattenColor(&out[dest]);
 	    if (cast->boost) ColorBoost(&out[dest]);
         }
      }
   }
}
