/* Apfelmännchen, Ausgabe als PGM-File (2 oder 5)  */

/* (C) 1996 Rene' Scholz  <mrz@informatik.uni-jena.de>  */

/* compile: gcc -O6 -s -o Apfel Apfel.c -lm */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

float m, xmin=-2.5,ymin=-1.5,xmax=1.5,ymax=1.5;  /* Grenzen des Bildausschnittes/Fractals */
int DEBUG=0;
int LOG=0;
int P2=0;
int P5=1;
int ScreenMaxX=1024, ScreenMaxY=768;
int MaxIter=150; // max. Anzahl der Iterationen --> auch Anzahl der Farben, def: 150

int mandel(register float Cx,register float Cy)
// Berechnet zum Punkt C=(Cx,Cy) aus Z den Farbwert des Fractals
// Z_n+1=(Z_n)²+C     Z_0=(0,0)
{
   const BLAU=1;
   register int i;
   register float x=0,y=0,x_old=0;
   for(i=1;i<MaxIter;i++)
     {  x=x*x-y*y   +Cx;
        y=2*x_old*y +Cy;
        x_old=x;
        if (x*x+y*y >4)
          if (LOG==1) { return(m*log(i+1)+1.0); }
                    else { return(i); }
     }
   return(BLAU);
}


void show_options()
{
   printf("Optionen:\n\n");
   printf("\t -help           Anzeige dieser Hilfe\n");
   printf("\t -xmin <Zahl>    linke  Begrenzung  (-4 < xmin < 4)  \n");
   printf("\t -ymin <Zahl>    untere Begrenzung  (-4 < ymin < 4)  \n");
   printf("\t -xmax <Zahl>    rechte Begrenzung  (-4 < xmax < 4)  \n");
   printf("\t -ymax <Zahl>    obere  Begrenzung  (-4 < xmax < 4)  \n");
   printf("\t -iter <1..255>  max. Iterationen          <Default=150>\n");
   printf("\t -log            Palette logarithmisch     <Default=normale Palette>\n");
   printf("\t -size  XxY      Bildgröße                 <Default=1024x768>\n");
   printf("\t -P5             Ausgabe als Bildtyp PGM5 auf stdout <Default>\n");
   printf("\t -P2             Ausgabe als Bildtyp PGM2 auf stdout \n");
   printf("\t -debug          Anzeige von Debugging-Informationen \n");
}

void show_help()
{
   system("clear");
   printf("\n\t\t\t Ausgabe eines Apfelmännchens als PGM-file \n\n\n");
   show_options();
}


void scan_options(int argc, char *argv[])
{
   int i,t,i1,i2;
   double f,f1,f2;
   char *s,*s1,*s2;

   for (i=1; i<argc; i++)
     {
        if (!strcmp ("-help", argv[i]) || !strcmp ("-h", argv[i]) )
          { show_help(); exit(0); }

        if (!strcmp ("-debug", argv[i]) ) { DEBUG=1; continue; }
        if (!strcmp ("-log", argv[i]) )   { LOG=1; continue; }
        if (!strcmp ("-P2", argv[i]) )    { P2=1; P5=0; continue; }
        if (!strcmp ("-P5", argv[i]) )    { P5=1; P2=0; continue; }

        if (!strcmp ("-size", argv[i]))
          {
             if (++i<argc)
               {
                  s=argv[i];
                  i1=atoi(strtok(s,"x")); i2=atoi(strtok(NULL,"x"));
                  if ((i1>0) && (i1<=2048)) { ScreenMaxX=i1; }
                  else {
                     printf("\nFehler: ScreenMaxX nicht zwischen 1 und 2048!\n");
                     show_options(); exit(-1);
                  }
                  if ((i2>0) && (i1<=2048)) { ScreenMaxY=i2; }
                  else {
                     printf("\nFehler: ScreenMaxY nicht zwischen 1 und 2048!\n");
                     show_options(); exit(-1);
                  }
               }
             else { printf("\nBildgröße fehlt !\n"); show_options(); exit(0); }
               continue;
          }

        if (!strcmp ("-iter", argv[i]))
          {
             if (++i<argc)
               {
                  t=atoi(argv[i]);
                  if ((1<=t) && (t<=255)) { MaxIter=t; }
                  else {
                     printf("\nFehler: Anzahl der Iterationen nicht zwischen 1 und 255 !\n");
                     show_options(); exit(-1);
                  }
               }
             else { printf("\nIterationsanzahl fehlt !\n"); show_options(); exit(0); }
               continue;
          }


        if (!strcmp ("-xmin", argv[i]))
          {
             if (++i<argc)
               {
                  f=atof(argv[i]);
                  if ((f<4) && (f>-4)) { xmin=f; }
                  else { printf("\nFehler: xmin nicht zwischen -4 und 4 !\n");
                         show_options(); exit(-1);
                  }
               }
             else { printf("\nParameter fehlt !\n"); show_options(); exit(-1); }
               continue;
          }

        if (!strcmp ("-ymin", argv[i]))
          {
             if (++i<argc)
               {
                  f=atof(argv[i]);
                  if ((f<4) && (f>-4)) { ymin=f; }
                  else { printf("\nFehler: ymin nicht zwischen -4 und 4 !\n");
                         show_options(); exit(-1);
                  }
               }
             else { printf("\nParameter fehlt !\n"); show_options(); exit(-1); }
               continue;
          }

        if (!strcmp ("-xmax", argv[i]))
          {
             if (++i<argc)
               {
                  f=atof(argv[i]);
                  if ((f<4) && (f>-4)) { xmax=f; }
                  else { printf("\nFehler: xmax nicht zwischen -4 und 4 !\n");
                         show_options(); exit(-1);
                  }
               }
             else { printf("\nParameter fehlt !\n"); show_options(); exit(-1); }
               continue;
          }

        if (!strcmp ("-ymax", argv[i]))
          {
             if (++i<argc)
               {
                  f=atof(argv[i]);
                  if ((f<4) && (f>-4)) { ymax=f; }
                  else { printf("\nFehler: ymax nicht zwischen -4 und 4 !\n");
                         show_options();
                         exit(-1);
                  }
               }
             else { printf("\nParameter fehlt !\n"); show_options(); exit(-1); }
               continue;
          }
        
        
        printf("\nFalsche Option !\n");        show_options();        exit(-1);
   }

}


void show_debugging_infos()
{
   fprintf(stderr,"\n\t\t Anzeige von Debugging-Informationen \n\n");
   fprintf(stderr,"\txmin = %f \n",xmin);
   fprintf(stderr,"\tymin = %f \n",ymin);
   fprintf(stderr,"\txmax = %f \n",xmax);
   fprintf(stderr,"\tymax = %f \n",ymax);
   fprintf(stderr,"\tScreenMaxX = %i \n",ScreenMaxX);
   fprintf(stderr,"\tScreenMaxY = %i \n",ScreenMaxY);
   fprintf(stderr,"\tMaxIter = %i \n",MaxIter);
   fprintf(stderr,"\tm = %f \n",m);
}


void print_pgm_header(int x,int y,char *pgm_type,int colors,char *name)
{
   printf("%s\n# created by %s\n# written by René Scholz <mrz@informatik.uni-jena.de>\n",pgm_type,name);
   printf("%d %d\n%d\n",x,y,colors);
}

void main(int argc, char *argv[])
{
   int x, y;
   float a,b;             /* C=(a,b) wird an mandel() übergeben */
   float StepX,StepY;

   scan_options(argc,argv);

   if (LOG==1) m=256.0/log((float)MaxIter);
   
   StepX=(xmax-xmin)/(ScreenMaxX-1);
   StepY=(ymax-ymin)/(ScreenMaxY-1);
   a=xmin; b=ymax;

   if (P5==1) { print_pgm_header(ScreenMaxX,ScreenMaxY,"P5",255,argv[0]); }
        else  { print_pgm_header(ScreenMaxX,ScreenMaxY,"P2",255,argv[0]); }
   
   for (y=1; y<=ScreenMaxY; y++) // Reihenfolge vertauscht, wegen Aufbau pgm-File
     {
        for (x=1; x<=ScreenMaxX; x++)
          {
            if (P5==1) { printf("%c",(char)mandel(a,b)); }  // pgm-5
                  else { printf("%d ",mandel(a,b)); }       // pgm-2
             a+=StepX;
          }
        if (P2==1) printf("\n");                             // pgm-2, besser lesbar
        a=xmin;
        b-=StepY;
     }
  
   if (DEBUG==1) show_debugging_infos();
   exit(0);
}