/* 
Idea taken from EffecTV http://effectv.sourceforge.net/
Written by Kent Mein mein@cs.umn.edu
http://www.cs.umn.edu/~mein/blender
Date: Tue Apr 23 18:35:36 CDT 2002
*/

#include "plugin.h"
#define DEPTH 4
enum { UP, DOWN, RIGHT, LEFT };

/* ******************** GLOBAL VARIABLES ***************** */
char name[24]= "Dice";	

/* structure for buttons, 
 *  butcode      name           default  min  max  0
 */

VarStruct varstr[]= {
   { LABEL,	"In: 1 strip", 0.0, 0.0, 0.0, ""}, 
   { NUM|INT,	"Cube SizeX",	    15.0,	1.0,	2000.0, "Width"}, 
   { NUM|INT,	"Cube SizeY",	    15.0,	1.0,	2000.0, "Height"}, 
   { NUM|FLO,	"Seed", 0.0,	0.0,	1.0, ""}, 
   { NUM|INT,	"Animate",	    0.0,	0.0,	1.0, "Change Dir by frame"}, 
   { NUM|INT,	"Grow",	    0.0,	0.0,	1.0, "Make cubes grow"}, 
};

/* 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;			/* because of the 'label' button */
	int stepx, stepy;
	float seed;
        int anim, grow;
} Cast;


/* cfra: the current frame */

float cfra;

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

/* ******************** Fixed functions ***************** */

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 plugin_seq_doit(Cast *cast, float facf0, float facf1, int xo, int yo, 
	ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *outbuf, ImBuf *use) {
   int x, y, stepx, stepy, c,d, maxx, maxy, type, i, j, r, xsum, ysum;
   char *out=(char *)outbuf->rect;
   char *in=(char *)ibuf1->rect;
   if (cast->grow) {
      stepx = FLOOR(facf0 * cast->stepx);
      stepy = FLOOR(facf0 * cast->stepy);
   } else {
      stepx = cast->stepx;
      stepy = cast->stepy;
   }
   if (stepx == 0) stepx++;
   if (stepy == 0) stepy++;

   if (cast->anim) {
      srand(cast->seed + cfra);
   } else {
      srand(cast->seed);
   }
   /* Step through the cubes */
   for(y=0;y<yo-1;y=y+stepy) {
      if ((yo + stepy) > yo) maxy = stepy;
      else maxy = yo -y;
      for(x=0;x<xo-1;x=x+stepx) {
         type = rand() % 4;
         if (xo < xo + stepx) maxx = stepx;
         else maxx =  xo - x;
         /* do a cube */
         for(i=0;i<maxx;i++) {
            for (j=0;j<maxy;j++) {
               ysum = y+j;
               if (ysum > yo) ysum -= yo;
               xsum = x+i;
               if (xsum > xo) xsum-= xo;
               c=(ysum * xo + xsum) * DEPTH;
               switch (type) {
                  case UP:
                     for(r=0;r<DEPTH;r++) out[c+r] = in[c+r];
                     break;
                  case DOWN:
                     ysum = y+stepy-j;
                     if (ysum > yo) ysum -= yo;
                     xsum = x + stepx - i;
                     if (xsum > xo) xsum -= xo;
                     d=(ysum * xo + xsum) * DEPTH;
                     for (r=0;r<DEPTH;r++) out[c+r] = in[d + r];
                     break;
                  case LEFT:
                     ysum = y+j;
                     if (ysum > yo) ysum -= yo;
                     xsum = x + stepx - i;
                     if (xsum > xo) xsum -= xo;
                     d=(ysum * xo + xsum) * DEPTH;
                     for (r=0;r<DEPTH;r++) out[c+r] = in[d + r];
                     break;
                  case RIGHT:
                     ysum = y+stepy-j;
                     if (ysum > yo) ysum -= yo;
                     xsum = x + i;
                     if (xsum > xo) xsum -= xo;
                     d=(ysum * xo + xsum) * DEPTH;
                     for (r=0;r<DEPTH;r++) out[c+r] = in[d + r];
                     break;
               }
            }
         }
      }
   }
}
