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

char name[24]= "videopatterns";

VarStruct varstr[]= {
	{ LABEL,		"Video Patterns", 0.0, 0.0, 0.0, ""}, 
	{ LABEL,		"by Adam Moss", 0.0, 0.0, 0.0, ""}, 
	{ LABEL,		"", 0.0, 0.0, 0.0, ""}, 
	{ NUM|INT,	"pattern: ",		5.0,	0.0, 8.0, 
	   "RGB Pattern Mode (0-8)"}, 
	{ LABEL,		"", 0.0, 0.0, 0.0, ""}, 
	{ TOG|INT,	"additive",			1.0,	0.0, 1.0, 
	   "toggle Additive mode"}, 
	{ TOG|INT,	"rotate",			0.0,	0.0, 1.0, 
	   "rotate RGB pattern"}, 
};

typedef struct Cast {
	int dummy;			/* because of the 'label' button */
	int dummy1;			/* because of the 'label' button */
	int dummy2;			/* because of the 'label' button */
	int pattern;
	int dummy3;			/* because of the 'label' button */
	int additive;
	int rotate;
} Cast;

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) {
}

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;
}


#define MAX_PATTERNS 9

#define MAX_PATTERN_SIZE 108

const int pattern_width[MAX_PATTERNS] = {2,4,1,1,2,3,6,6,5};
const int pattern_height[MAX_PATTERNS] = {6,12,3,6,12,3,6,18,15};
const char *pattern_name[MAX_PATTERNS] = {
  "Staggered",
  "Large staggered",
  "Striped",
  "Wide-striped",
  "Long-staggered",
  "3x3",
  "Large 3x3",
  "Hex",
  "Dots",
};

const int pattern[MAX_PATTERNS][MAX_PATTERN_SIZE] =
{
  {
    0,1,
    0,2,
    1,2,
    1,0,
    2,0,
    2,1,
  },
  {
    0,0,1,1,
    0,0,1,1,
    0,0,2,2,
    0,0,2,2,
    1,1,2,2,
    1,1,2,2,
    1,1,0,0,
    1,1,0,0,
    2,2,0,0,
    2,2,0,0,
    2,2,1,1,
    2,2,1,1,
  },
  {
    0,
    1,
    2,
  },
  {
    0,
    0,
    1,
    1,
    2,
    2,
  },
  {
    0,1,
    0,1,
    0,2,
    0,2,
    1,2,
    1,2,
    1,0,
    1,0,
    2,0,
    2,0,
    2,1,
    2,1,
  },
  {
    0,1,2,
    2,0,1,
    1,2,0,
  },
  {
    0,0,1,1,2,2,
    0,0,1,1,2,2,
    2,2,0,0,1,1,
    2,2,0,0,1,1,
    1,1,2,2,0,0,
    1,1,2,2,0,0,
  },
  {
    2,2,0,0,0,0,
    2,2,2,0,0,2,
    2,2,2,2,2,2,
    2,2,2,1,1,2,
    2,2,1,1,1,1,
    1,1,1,1,1,1,
    0,0,1,1,1,1,
    0,0,0,1,1,0,
    0,0,0,0,0,0,
    0,0,0,2,2,0,
    0,0,2,2,2,2,
    2,2,2,2,2,2,
    1,1,2,2,2,2,
    1,1,1,2,2,1,
    1,1,1,1,1,1,
    1,1,1,0,0,1,
    1,1,0,0,0,0,
    0,0,0,0,0,0,
  },
  {
    0,1,2,0,0,
    1,1,1,2,0,
    0,1,2,2,2,
    0,0,1,2,0,
    0,1,1,1,2,
    2,0,1,2,2,
    0,0,0,1,2,
    2,0,1,1,1,
    2,2,0,1,2,
    2,0,0,0,1,
    1,2,0,1,1,
    2,2,2,0,1,
    1,2,0,0,0,
    1,1,2,0,1,
    1,2,2,2,0,
  }
};


#define PREVIEW_WIDTH 100
#define PREVIEW_HEIGHT 100

typedef struct {
  int pattern_number;
  int additive;
  int rotated;
} VideoValues;

static VideoValues vvals =
{
  3,
  FALSE,
  FALSE,
};

static void
video_render_row(const unsigned char *src_row,
					   unsigned char *dest_row,
					int row,
					int rotated,
					int additive,
					int pattern_number,
					int row_width,
					int bytes);



static void
video_render_row (const unsigned char *src_row,
		  unsigned char *dest_row,
		  int row,
		  int rotated,
		  int additive,
		  int pattern_number,
		  int row_width,
		  int bytes)
{
  int col, bytenum;

  for (col = 0; col < row_width ; col++)
    {
      for (bytenum = 0; bytenum<bytes; bytenum++)
	{
	  if (rotated)
	    {
	      if (bytenum<3)
		{
		  if (pattern[pattern_number]
		      [pattern_width[pattern_number]*
		      (col%pattern_height[pattern_number]) +
		      row%pattern_width[pattern_number] ] == bytenum)
		    {
		      dest_row[col*bytes+bytenum] =
			src_row[col*bytes+bytenum];
		    }
		  else
		    {
		      dest_row[col*bytes+bytenum] = 0;
		    }
		}
	      else
		{
		  dest_row[col*bytes + bytenum] =
		    src_row[col*bytes + bytenum];
		}
	    }
	  else
	    {
	      if (bytenum<3)
		{
		  if (pattern[vvals.pattern_number]
		      [pattern_width[vvals.pattern_number]*
		      (row%pattern_height[vvals.pattern_number]) +
		      col%pattern_width[vvals.pattern_number] ] == bytenum)
		    {
		      dest_row[col*bytes+bytenum] =
			src_row[col*bytes+bytenum];
		    }
		  else
		    {
		      dest_row[col*bytes+bytenum] = 0;
		    }
		}
	      else
		{
		  dest_row[col*bytes + bytenum] =
		    src_row[col*bytes + bytenum];
		}
	    }
	}
    }

  if (additive)
    {
      for (col = 0; col < row_width ; col++)
	{
	  for (bytenum = 0; bytenum<bytes; bytenum++)
	    {
	      if (bytenum<3)
		{
		  dest_row[col*bytes + bytenum] =
		    (
		     (int)((int) dest_row[col*bytes + bytenum] +
			    (int) src_row[col*bytes + bytenum])
		     ) < 255 ?
		    (
		     (int)((int) dest_row[col*bytes + bytenum] +
			    (int) src_row[col*bytes + bytenum])
		     ) : 255;
		}
	    }
	}
    }
}



void plugin_seq_doit(Cast *cast, float facf0, float facf1, int sx, int sy, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use)
{
  int c;
  int bytes;
  unsigned char  *dest_row  = (unsigned char *) out->rect;
  unsigned char  *src_row = (unsigned char *) ibuf1->rect;
  int row;

  bytes = 4;

  vvals.rotated = cast->rotate;
  vvals.pattern_number = cast->pattern;
  vvals.additive = cast->additive;

  for (row = 0; row < ibuf1->y; row++)
    {

      video_render_row (src_row,
			dest_row,
			row,
			vvals.rotated,
			vvals.additive,
			vvals.pattern_number,
			out->x,
			bytes
			);

      for (c = 0; c < out->x; c++) {
		*(dest_row++);
		*(dest_row++);
		*(dest_row++);
		*(dest_row++);
		*(src_row++);
		*(src_row++);
		*(src_row++);
		*(src_row++);
	  }
  }
}

