/*
 * This is a texture plugin for blender 1.60 or above.
 *
 * Brick-drawing plugin, based on a sample plugin from NaN
 * 
 */

/* This plugin will surely be wrongly calculated. This was something 
 * like my first maths using experiment. If there is something wrong
 * with this plugin please inform me. e-mail: unicorn@rieska.oulu.fi */
 
#include "math.h"
#include "plugin.h"

/* ******************** GLOBAL VARIABLES ***************** */

char name[]= "Bricks";

/* Subtype names must be less than 15 characters */

#define NR_TYPES   1
char stnames[NR_TYPES][16]= {"Bricks"};

VarStruct varstr[]= {
  { NUM|FLO,  "Width",        0.550, 0.0,  1.0,  "Brick Width"},
  { NUM|FLO,  "Height",        0.350, 0.0,  1.0,  "Brick Height"},
  { NUM|FLO,  "Thickness",     0.050, 0.0,  1.0,  "Mortar Thickness"},
  { TOG|INT,  "Bump",          0,     0,    1,    "Bump the texture"},
  { NUM|FLO,  "BumpHeight",    0.3,   0.0,  1.0,  "Bumpmap Height"},
  { NUM|FLO,  "BumpWidth",     0.5,   0.0,  0.999,
   "Thickness * this value is Bumpmap Width"},
};

/* 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 
{
  float width;
  float height;
  float thick;
  int   bump;
  float bumpheight;
  float bumpwidth;
} Cast;

float result[8];

/* cfra: the current frame */

float cfra;

int plugin_tex_doit(int, Cast *, float *, float *, float *);


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

int plugin_tex_getversion(void) 
{   
   return B_PLUGIN_VERSION;
}

void plugin_but_changed(int but) 
{
}

void plugin_init(void)
{
}

/* this function should not be changed: */

void plugin_getinfo(PluginInfo *info)
{
   info->name= name;
   info->stypes= NR_TYPES;
   info->nvars= sizeof(varstr)/sizeof(VarStruct);
   
   info->snames= stnames[0];
   info->result= result;
   info->cfra= &cfra;
   info->varstr= varstr;

   info->init= plugin_init;
   info->tex_doit=  (TexDoit) plugin_tex_doit;
   info->callback= plugin_but_changed;
}

float stp(float a, float x)
{
   return (float)(x >= a);
}

float mod(float a, float b)
{
   int n = (int) (a/b);
   a -= n*b;
   if(a < 0)
     a += b;
   return a;
}
 
int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt)
{
  float x,y;
  float bmwidth, bmheight, mwf, mhf;
  float brickx, bricky, xx, yy, w, h;
  float n[3], part, kx, ky, partw, parth;
  
  x = texvec[0];
  y = texvec[1];

  /* iniatlize n[0] */
  n[0] = 0;
  
  /* Total w & h */
  bmwidth  = cast->width + cast->thick;
  bmheight = cast->height + cast->thick;
  
  /* Mortar thicks */
  mwf = cast->thick * 0.5 / bmwidth;
  mhf = cast->thick * 0.5 / bmheight;
  
  /* Check brick */
  xx = x/bmwidth;
  yy = y/bmheight;
  
  /* Check row */
  if(mod(yy*0.5,1) > 0.5)
    xx += 0.5;
  
  /* Set brick */
  brickx = floor(xx);
  bricky = floor(yy);
  
  xx -= brickx;
  yy -= bricky;
  
  /* Where in the brick */
  w = stp(mwf, xx) - stp(1-mwf,xx);
  h = stp(mhf, yy) - stp(1-mhf,yy);
  
  if(w*h)
    result[0] = 0.0;
  else
    result[0] = 1.0;


  /* Calculate part of thick */
  part  = (1-cast->bumpwidth)*cast->thick*0.5;
  partw = (1-cast->bumpwidth) * mwf;
  parth = (1-cast->bumpwidth) * mhf;

  /* Calculate some "kulmakerroin" what ever it is in english */
  kx = (part/bmwidth)/(part/bmheight);
  ky = (part/bmheight)/(part/bmwidth);
  

  /* Check that we really are on the side and the check that we fill the whole side and
   * those triangular areas so the brick will look like 3D even it is 2D */
  if(w == 0 && yy >= ky*xx && yy <= 1-(ky*xx) || yy >= ky*(1-xx) && yy <= 1-(ky*(1-xx)))
  {
    
    /* Check if we are looking from different side */
    if(xx < mwf)
      n[0] *= -1;
    
    /* Calculate difference vector and check that we are on the 3D area */
    if((xx > partw && xx < mwf) || (xx > 1-mwf && xx < 1-partw))
    {
      result[5] += n[0];
      result[6] += n[1];
      result[7] += 1 - n[2];      
    }
  }
  
  /* Some checks there for top and bottom 3D bars */
  if(h == 0 && xx > kx*yy && xx < 1-(kx*yy) || xx > kx*(1-yy) && xx < 1-(kx*(1-yy)))
  {
    /* Check the side we are looking from */
    if(yy < mhf)
      n[1] *= -1;

    /* Calculate difference vector */
    if((yy > parth && yy < mhf) || (yy > 1-mhf && yy < 1-parth))
    {
      result[5] += n[0];
      result[6] += n[1];
      result[7] += 1 - n[2];            
    }       
  }
    
  if(cast->bump)
    return 2;
  else
    return 0;
}
