
/************************************************************************/
#define OP_NAME      "pnmwhitenoise"
#define VERSION      "1.02"
#define DATE         "31.01.98"
#define AUTHOR       "Stefan Diener"
/************************************************************************/

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <sys/types.h>

#include <STIMP/pnm.c>

struct PNM_Info source;
static BOOL Gleichv=TRUE;
static int Streuung=75;

double RND_EQU(void)
/* Gleichverteilung */
{
  long int a=31415821, x, y;
  long int p=100000;   // p=100000000;
  long int am, rm, q, ar, rr;

  y=(long int) rand();
  q=(long int) sqrt((double) p); 

  am=(long int) a/q;
  ar=a%q;

  rm=(long int) y/q;
  rr=y%q;

  x=q*((am*rr+ar*rm)%q)+ar*rr;
  y=(x+1)%p;

  return (double)y/(double)p;
}

double RND_NORM(void)
/* Normalverteilung */
{
  double t=-0.5, r, s;

  while ((t<0) || (t>1))
  {
    r=2*RND_EQU()-1;
    s=2*RND_EQU()-1;
    t=r*r+s*s;
  }

  return (fabs(r)*sqrt((-2.0)*log(t)/t)/2.0);
}

void Do_It(void)
{
  int i, w, ende;
  unsigned char *srcR,*srcG, *srcB;

  if (source.type==TYPE_PPM)
  {
    srcR=source.redDATA;
    srcG=source.greenDATA;
    srcB=source.blueDATA;
  }
  else srcR=source.DATA;

  /* neue Folge von Zufallszahlen erzeugen */
  srand((unsigned)time(NULL));

  /* Anzahl von Bildpunkten */
  ende=source.height*source.width;

  if (Gleichv)   /* Gleichverteilung */
  {
    for (i=0; i<ende; i++)
    {
      w=(int) floor((*srcR)+Streuung*RND_EQU());
      *srcR++=(w<source.maxval) ? w : source.maxval;

      if (source.type==TYPE_PPM)
      {
        w=(int) floor((*srcG)+Streuung*RND_EQU());
        *srcG++=(w<source.maxval) ? w : source.maxval;

        w=(int) floor((*srcB)+Streuung*RND_EQU());
        *srcB++=(w<source.maxval) ? w : source.maxval;
      }
    }
  }
  else   /* Normalverteilung */
  {
    for (i=0; i<ende; i++)
    {
      w=(int) floor((*srcR)+Streuung*RND_NORM());
      *srcR++=(w<source.maxval) ? w : source.maxval;

      if (source.type==TYPE_PPM)
      {
        w=(int) floor((*srcG)+Streuung*RND_NORM());
        *srcG++=(w<source.maxval) ? w : source.maxval;

        w=(int) floor((*srcB)+Streuung*RND_NORM());
        *srcB++=(w<source.maxval) ? w : source.maxval;
      }
    }
  }
}

int main(int argc,char **argv)
/* Hauptprogramm */
{
  int i;
  unsigned char tempo[10];

  /* offizielle Begruessung */
  PrintOpening(argc,argv);

  /* Uebergebene Parameter auswerten */
  for (i=1; i<argc; i++)
  {
    if ((argv[i][0]=='-') && argv[i][1])
    {
      switch (argv[i][1])
      {
        case 'e': Gleichv=TRUE;
                      break;

        case 'n': Gleichv=FALSE;
                      break;

        case 's': strncpy(tempo, argv[i], 9);
                      tempo[0]=32;
                      tempo[1]=32;
                      if (sscanf(tempo,"%i",&Streuung)!=1) Streuung=-1;
                      if ((Streuung<0) || (Streuung>150))
                      {
                        PrintMessage("Wrong value for the scatter !");
                        Hilfe();
                        exit(-1);
                      }
                      break;

        case 'v': beVerbose=FALSE;
                      break;

        default: PrintMessage("Unknown parameter: %s", argv[i]);
                     Hilfe();
                     exit(-1);
                     break;
      }
    }

    if (argv[i][0]=='+')
    {
      switch (argv[i][1])
      {
        case 'v': beVerbose=TRUE;
                      break;

        default: PrintMessage("Unknown parameter: %s", argv[i]);
                     Hilfe();
                     exit(-1);
                     break;
      }
    }
  }

  /* Mindestzahl der Argumente pruefen */
  if (argc<3)
  {
    PrintMessage("Wrong number of arguments !");
    Hilfe();
    exit(-1);
  }

  /* Anzahl der Dateinamen überprüfen */
  if (FilenameCount(argc, argv)!=2)
  {
    PrintMessage("Wrong number of file names !");
    Hilfe();
    exit(-1);
  }

  if (ReadPNMFile(GetFilename(1,argc,argv), TYPE_PNM, &source)==0)
  {
    PrintMessage("Working ...");
    Do_It();

    WritePNMFile(GetFilename(2,argc,argv), &source);
    FreePNMArray(&source);
  }

  PrintClosing();
  exit(0);
}

