
/* 
 * This is a texture plugin for blender 1.60 or above.
 *
 * Dot-drawing plugin, based on a sample plugin from NaN
 * Copyright (c) 1999, Bernd Breitenbach
 *
 * $Id: dots2.c,v 1.5 1999/06/28 18:41:48 bernd Exp bernd $
 * 
 */

/* ************************************************************
	NOTE: This software comes with absolute no warranty.
	You may distribute, modify and use it free of charge.
	
	If you have any enhancements or bug fixes, please let me now:

	              breitenb@iml.fhg.de
   ************************************************************ */

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


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

char name[]= "Dots";
char *release="$Revision: 1.5 $";

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

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

VarStruct varstr[]= {
  {LABEL|FLO,"V1.5   bb",        0,      0,   0,  ""},
  {TOG|INT,  "Single",	       0.0,  0.0, 1.0,  "Creates only a single dot"}, 
  {NUM|FLO,  "Size",	       0.25, 0.001, 1.0,  "The size of each dot"}, 
  {NUM|FLO,  "Noise",	       0.0,  0.0, 10.0, "Noise parameter: 0. means no noise"},
  {TOG|INT,  "Smooth",	       0.0,  0.0, 1.0,  "Smooth dots"},
  {TOG|INT,  "Bump",           0.0,  0.0, 1.0,  "Turn on bump-mapping"},
  {NUM|FLO,  "Bump Size",      1.0,  -5.0, 5.0,  "Height of the bumps"},
  {TOG|INT,  "No AAlias",      0.0,  0.0, 1.0,  "Turn antialias off (independent from render settings)"}
};

/* 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 dummy;
        int  single;
	float size;
	float noise;
        int  smooth;
        int  bump;
        float  bump_size;
        int  noaalias;
} Cast;

/* result: 
   Intensity, R, G, B, Alpha, nor.x, nor.y, nor.z
 */

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

/* ************************************************************
	Dots2
	
	This plugin is an enhancement of my dots plugin.
	It is placing  dots of size 'size' on the vertices 
	of a regular triangle lattice covering the x-y-plane. 
	With 'smooth' you can choose between dots with a sharp border, 
	or smooth dots with a texture value that is raising
	from 0. at the border to 1. at the center.

	With bump and 'bump size' you can create dots raising from the 
	plane.

	Apart from smoothing dots, anti-aliasing is performed by
	calculating the mean value from four texture values at
	the vertices of an pixel. This can be turned off by
	toggle the 'no aalias'-button
   ************************************************************ */

#define SQRT3 (1.73205080756888)
#define SQRT3_2 (SQRT3/2.)
#define BFAC (0.2)
#define EPS (0.0001)


void calc_dot_value(Cast *cast,float x,float y)
{ 
  float size2=cast->size*cast->size,dist2;
  float isize2=size2*0.64;
  float bsize=cast->bump_size/4.;
  float xsign=bsize,ysign=bsize;
  float val=0.;

  /* First we do a little origami: */
  if (x<0.) {
    x=fabs(x);
    xsign=-xsign;
  }
  if (y<0.) {
    y=fabs(y);
    ysign=-ysign;
  }

  if (!cast->single) {
    x=x-ffloor(x);
    y=y-ffloor(y/SQRT3)*SQRT3;

    if (x>0.5){
      x=1.-x;
      xsign=-xsign;
    }
    if (y>SQRT3_2) {
      y=SQRT3-y;
      ysign=-ysign;
    }
  }

  /* Now we have to check only two circles at (0,0) and (1/2,sqrt(3)/2) */

  dist2=x*x+y*y;

  if (dist2<=size2) {
    if (cast->smooth) {
      val=fsqrt(size2-dist2)/cast->size;
      result[0]+=val;
      if (cast->bump) {
	result[5]+=-xsign*x/cast->size;
	result[6]+=-ysign*y/cast->size;
      }
    } else {
      result[0]+=1.;
      if (cast->bump && dist2>isize2) {
	if (dist2<EPS) dist2=EPS;
	result[5]+=-xsign*x/dist2*BFAC;
	result[6]+=-ysign*y/dist2*BFAC;
      } 
    }
  } else if (!cast->single) {
    x=0.5-x;
    y=SQRT3_2-y;
    dist2=x*x+y*y;
    if (dist2<=size2) {
      if (cast->smooth) {
	val=fsqrt(size2-dist2)/cast->size;
	result[0]+=val;
	if (cast->bump) {
	  result[5]+=xsign*x/cast->size;
	  result[6]+=ysign*y/cast->size;
	}
      } else{
	result[0]+=1.;
	if (cast->bump && dist2>isize2) {
	  if (dist2<EPS) dist2=EPS;
	  result[5]+=xsign*x/dist2*BFAC;
	  result[6]+=ysign*y/dist2*BFAC;
	} 
      }
    }
  }
}



int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt)
{
  float x,y;

  x=texvec[0];
  y=texvec[1];
  if(cast->noise>0.001) {
    x+= hnoise(cast->noise, texvec[0], texvec[1], texvec[2]);
    y+= hnoise(cast->noise, texvec[1], texvec[2], texvec[0]);
  }

  result[0]=0.;
  result[5]=0.;
  result[6]=0.;
  result[7]=0.;
  calc_dot_value(cast,x,y);

  if (!cast->noaalias && dxt && dyt) {
    float offx=fabs(dxt[0])+fabs(dxt[1]);
    float offy=fabs(dyt[0])+fabs(dyt[1]);
    calc_dot_value(cast,x+offx,y);
    calc_dot_value(cast,x,y+offy);
    calc_dot_value(cast,x+offx,y+offy);
    result[0]/=4.0;
    result[5]/=4.0;
    result[6]/=4.0;
  }

  if (cast->bump)
    return 2;
  else
    return 0;
}





