
/* 
 * This is a texture plugin for blender 1.60 or above.
 *
 * Spiral-drawing plugin, based on a sample plugin from NaN
 * Copyright (c) 1999, Bernd Breitenbach
 *
 * $Id: spirals.c,v 1.7 1999/06/28 18:41:53 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"

#define DOUT(a) printf("%s\n",a);fflush(stdout) 

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

char name[]= "Spirals";
char *release="$Revision: 1.7 $";

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

#define NR_TYPES	2
char stnames[NR_TYPES][16]= {"Archim","Log"};

VarStruct varstr[]= {
  {LABEL|FLO,   "V1.7  bb",             0.,    0.,   0.,   ""},
  {NUM|INT,	"No.",			1.0,  1.0, 24.0,   "No. of spirals"}, 
	 
  {NUM|FLO,	"Windings",	        1.0,  0.0, 10.0,   "Winding parameter"},
  {NUM|FLO,	"Width",		0.1,  0.0, 1.0,    "Width of the spirals"},
  {NUM|FLO,	"Size",		        1.0,  0.0, 1000.0, "Size of the spirals"},
  {NUM|FLO,	"Rotation",	        0.0,  0.0, 360.0,  "Rotation of the pattern"},
  {NUM|FLO,	"Noise",		0.0,  0.0, 10.0,   "Noise parameter: 0. means no noise"},
  {NUM|INT,	"Value Mode",		0.0,  0.0, 7.0,    "Smooth Spirals"},
  {TOG|INT,	"No AAlias",	        0.0,  0.0, 1.0,    "Turn antialias off (independent from render settings)"},
  {NUM|FLO,     "Ani Speed",            0.0,-180., 180.,   "Rotation speed of the spiral"},
  {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"}
};

/* 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  no;
  float windings;
  float width;
  float size;
  float rotation;
  float noise;
  int  smooth;
  int  noaalias;
  float anispeed;
  int  bump;
  float  bump_size;
} 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)
{
  DOUT("checkpoint 1a");
  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;
  DOUT("checkpoint 1e");
}

/* ************************************************************
	Spirals
	
	These functions generate Archimedean or Logarithmic
	spirals. The spirals can be colored or animated.

	Anti-aliasing is performed by
	calculating the mean value from four texture values at
	the vertices of an pixel.
   ************************************************************ */

#ifndef M_PI
#define	M_PI 3.14159265358979323846
#endif
#undef M_PI2
#define M_PI2 (M_PI*2.)
#ifndef M_PI_2
#define M_PI_2 (M_PI*0.5)
#endif


#define FLAT    (0)
#define LINEAR  (1)
#define DLINEAR (2)
#define QUAD    (3)
#define MULTI   (4)

float texvalue(float val,int mode,int a,int b)
{
  int multi=mode & MULTI;
  float retval;
  mode=mode & ~MULTI;

  if (mode==FLAT)
    retval=1.;
  else if (mode==LINEAR)
    retval=val;
  else if (mode==DLINEAR)
    retval=1-fabs(val-0.5);
  else { /* QUAD */
    val=2*val-1.;
    retval=1-val*val;
  }
  if (multi) {
    retval=(retval+a)/b;
  }
  return retval;
}


void bumpvalue(Cast *cast,float val,float phi)
{
  val=2.*val-1.;
  result[5]+=val*cos(phi)*cast->bump_size;
  result[6]+=val*sin(phi)*cast->bump_size;
}

float calc_log_spiral(Cast *cast,float r,float phi)
{
  float retval=0.,phi_r;
  float frac;
  float w=M_PI2*cast->width/cast->no;
  int i;

  phi_r=(cast->rotation+cast->anispeed*cfra)/180.*M_PI+log(r+1.)*cast->windings*8.;
    
  for(i=0;i<cast->no;i++) {
    phi_r-=((int)(phi_r/M_PI2))*M_PI2;

    if (phi>phi_r) {
      frac=(phi-phi_r)/w;
      if (frac<1.) {
	retval=texvalue(frac,cast->smooth,i,cast->no);
	if (cast->bump) bumpvalue(cast,frac,phi);
	break;
      }
    }else{
      float phi2=phi+M_PI2;
      if (phi2>phi_r) {
	frac=(phi2-phi_r)/w;
	if (frac<1.) {
	  retval=texvalue(frac,cast->smooth,i,cast->no);
	  if (cast->bump) bumpvalue(cast,frac,phi);
	  break;
	}
      }
    }
    phi_r+=M_PI2/cast->no;
  }
  return retval;
}



float calc_arch_spiral(Cast *cast,float r,float phi)
{
  float retval=0.,d=1./cast->windings;
  float v,w=cast->width/cast->no;
  int i;

  phi=M_PI2-phi;
  phi+=(cast->rotation+cast->anispeed*cfra)/180.*M_PI;
  r+=phi/(M_PI2*cast->windings);
  for(i=0;i<cast->no;i++) {
    v=r/d-(int)(r/d);
    if (v<w) {
      v=v/w;
      retval=texvalue(v,cast->smooth,i,cast->no);
      if (cast->bump) bumpvalue(cast,v,phi);
      break;
    }
    r+=d/cast->no;
  }
  return retval;
}


float calc_value(int stype,Cast *cast,float x,float y)
{
  float retval=0.,phi=0.,r,frac;

  x*=cast->size;
  y*=cast->size;
  if (x!=0. || y!=0.) {
    phi+=atan2(x,y);
    if (phi<0.) phi+=M_PI2;
  }
  r=fsqrt(x*x+y*y);

  if (cast->windings<0.0001) {
    float phisec,v;
    int n;

    phi+=(cast->rotation+cast->anispeed*cfra)/180.*M_PI;
    phisec=M_PI2/cast->no;
    n=(int)(phi/phisec);
    phi-=n*phisec;
    v=M_PI2*cast->width/cast->no;
    if (phi<v) {
      frac=phi/v;
      retval=texvalue(frac,cast->smooth,n,cast->no);
      if (cast->bump) {
	phi+=M_PI_2;
	bumpvalue(cast,frac,phi);
      }
    }
  } else {
    if (stype==0) 
      retval=calc_arch_spiral(cast,r,phi);
    else 
      retval=calc_log_spiral(cast,r,phi);
  }
  return retval;
}


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

  x=texvec[0];
  y=texvec[1];

  result[5]=0.;
  result[6]=0.;
  result[7]=0.;
  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]=calc_value(stype,cast,x,y);

  if (!cast->noaalias && dxt && dyt) {
    float offx=fabs(dxt[0])+fabs(dxt[1]);
    float offy=fabs(dyt[0])+fabs(dyt[1]);
    result[0]+=calc_value(stype,cast,x+offx,y);
    result[0]+=calc_value(stype,cast,x,y+offy);
    result[0]+=calc_value(stype,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;
}





