/**************************************************************************/
/* cos3d2.c                                                    28.12.87   */
/* Version 1.0                                                            */
/*                                                                        */
/* Filmanimation                                                          */
/* Phasenverschiebung                                                     */
/*                                                                        */
/* fuer Markt+Technik geschrieben von Heiko Knappe                        */
/*                                                                        */
/* Komplexe Dynamische Systeme                                            */
/**************************************************************************/


#include <exec/types.h>
#include <math.h>
#include <intuition/intuition.h>

#define WIDTH   320  /* Screen Modus */
#define HEIGHT  250
#define DEPTH   5
#define FLAGS   0 /*HIRES+LACE*/
#define FWIDTH  200
#define FHEIGHT 100
#define FXOFF   120
#define FYOFF   100
#define BILDANZAHL 9
#define STEP .222222

#define N 100         /* Anzahl der Stuetzpunkte in x,y Richtung */


extern short save();

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Screen *MyScreen;
struct RastPort *MyRastPort;
struct AreaInfo MyAreaInfo;
struct TmpRas MyTmpRas;
struct NewScreen MyNewScreen=
 {0,0,WIDTH,HEIGHT,DEPTH,1,0,FLAGS,CUSTOMSCREEN,0,0,0,0};

float rmin=-PI,rmax=PI;      /* Grenzen des Bildes                  */
float imin=-PI,imax=PI;
float rst,ist;
float re,im,h;
int   i,j,k,bild;
short land[N][N];            /* Feld mit den Punktwerten            */
short x[4],y[4];             /* 4 Eckpunkte der Flaechen            */
short stx,sty;
short anzcol,col1,col2;
UWORD buffer[5*10];          /* Variablen fuer AreaFill             */
long  *speicher;
short bx=0,by=1,bz=1;        /* Beleuchtungsvektor                  */
float b;
float c=0;
char  file_name[20]="pic",num[10];


/***********************/
/* Hauptprogramm       */
/***********************/

main()
{
 open_things();
 for(bild=0;bild<BILDANZAHL;++bild,c+=STEP)
 {
    sin_3d();
    ausgabe();
    itoa(bild,num);
    strcpy(file_name+3,num);
    if(save(file_name,1,MyScreen)!=TRUE) break; /* Fehler?*/
 }
 close_things();
}

/* Hilfsfunktion (int nach ASCII) */
itoa(wert,buff)
int wert;
char buff[];
{
 int i,j,sign;
 char c;

 if((sign=wert)<0)
    wert=-wert;
 i=0;
 do
 {
    buff[i++]=wert%10+'0';
 }
 while((wert/=10)>0);
 if(sign<0)
    buff[i++]='-';
 buff[i]=0;
 for(i=0,j=strlen(buff)-1;i<j;i++,j--)
 {
    c=buff[i];
    buff[i]=buff[j];
    buff[j]=c;
 }
}


/***********************/
/* Initialisierung     */
/***********************/

open_things()
{
 if((IntuitionBase=OpenLibrary("intuition.library",0))==0)
    close_things();
 if((GfxBase=OpenLibrary("graphics.library",0))==0)
    close_things();
 if((MyScreen=OpenScreen(&MyNewScreen))==0)
    close_things();
 MyRastPort=&(MyScreen->RastPort);
 init_colors();
 init_fill();
 b=sqrt((float)(bx*bx+by*by+bz*bz));
} 

init_fill()
{
 if((speicher=AllocRaster(WIDTH,HEIGHT))==0)
    close_things();
 MyRastPort->AreaInfo=&MyAreaInfo;
 MyRastPort->TmpRas=InitTmpRas(&MyTmpRas,speicher,RASSIZE(WIDTH,HEIGHT));
 InitArea(&MyAreaInfo,&buffer[0],10);
}

close_things()
{
 if(speicher!=0) FreeRaster(speicher,WIDTH,HEIGHT);
 if(IntuitionBase!=0) CloseLibrary(IntuitionBase);
 if(GfxBase!=0) CloseLibrary(GfxBase);
 if(MyScreen!=0) CloseScreen(MyScreen);
 exit();
} 

init_colors()
{
 for(i=0,anzcol=1;i<DEPTH;anzcol*=2,++i);
 SetRGB4(&(MyScreen->ViewPort),0,0,0,0); /* Hintergrund schwarz */
 for(i=1;i<=anzcol/2;++i)
 {
    SetRGB4(&(MyScreen->ViewPort),2*i,
            (short)((float)i/anzcol*15*2),0,5);
    SetRGB4(&(MyScreen->ViewPort),2*i-1,
            (short)((float)i/anzcol*15*2),0,5);
 }
}


/***********************/
/* Berechnung der      */
/* Stuetzpunkte        */
/***********************/

sin_3d()
{
 printf("Berechnung der Stuetzpunkte fuer Bild %d\n",bild);
 rst=(rmax-rmin)/N;
 ist=(imax-imin)/N;
 for(i=0;i<N;++i) /* in x-Richtung */
 {
    re=rmin+i*rst;
    for(j=0;j<N;++j) /* in y-Richtung */
    {
       im=imin+j*ist;
       h=(re*re+im*im);
       land[i][j]=(short)(cos(h+c*PI)*20)+50;
    }
 }
 printf("-> fertig\n");
}


/***********************/
/* Ausgabe             */
/***********************/

ausgabe()
{
 SetRast(MyRastPort,0); /* Bild loeschen */
 stx=FWIDTH/N,sty=FHEIGHT/N;
 for(i=0;i<N-1;++i)
 {
     for(j=0;j<N-1;++j)
     {
        /* Berechnung der Eckpunkte der Flaechen */
        x[0]=FXOFF+stx*i-sty*j,y[0]=FYOFF-land[i][j]+sty*j;
        x[1]=FXOFF+stx*(i+1)-sty*j,y[1]=FYOFF-land[i+1][j]+sty*j;
        x[2]=FXOFF+stx*(i+1)-sty*(j+1),y[2]=FYOFF-land[i+1][j+1]+sty*(j+1);
        x[3]=FXOFF+stx*i-sty*(j+1),y[3]=FYOFF-land[i][j+1]+sty*(j+1);
        for(k=0;k<3;++k)
           if(y[k]<0) y[k]=0;
        zeich();
     }
 }
}

zeich()
{
 farbe();
 SetAPen(MyRastPort,anzcol-col1);  /* Flaeche1 zeichnen */
 AreaMove(MyRastPort,x[0],y[0]); AreaDraw(MyRastPort,x[1],y[1]);
 AreaDraw(MyRastPort,x[2],y[2]); AreaEnd(MyRastPort);
 SetAPen(MyRastPort,anzcol-col2);  /* Flaeche2 zeichnen */
 AreaMove(MyRastPort,x[0],y[0]); AreaDraw(MyRastPort,x[3],y[3]);
 AreaDraw(MyRastPort,x[2],y[2]); AreaEnd(MyRastPort);
}

farbe()  /* Berechnung der Farbe einer Flaeche */
{
 float n,h;
 int nx,ny,nz;
 short v1x,v1y,v1z,v2x,v2y,v2z;

 /* 1. Flaeche */
 v1x=1,v1y=0,v1z=land[i+1][j]-land[i][j];
 v2x=0,v2y=1,v2z=land[i+1][j+1]-land[i][j];
 nx=v1y*v2z-v1z*v2y,ny=v1z*v2x-v1x*v2z,nz=v1x*v2y-v1y*v2x;
 n=sqrt((float)(nx*nx+ny*ny+nz*nz));
 if(n==0) col1=1;
 h=acos((float)(nx*bx+ny*by+nz*bz)/b/n)-PI/2;
 h=(h<0)? -h : h;
 if((col1=(short)((PI/2-h)*(anzcol-1)*2/PI)+1)>(anzcol-1)) col1=anzcol-1;
 if(col1<=0) col1=1;
 /* 2. Flaeche */
 v1x=1,v1y=0,v1z=land[i][j+1]-land[i][j];
 v2x=0,v2y=1,v2z=land[i+1][j+1]-land[i][j];
 nx=v1y*v2z-v1z*v2y,ny=v1z*v2x-v1x*v2z,nz=v1x*v2y-v1y*v2x;
 n=sqrt((float)(nx*nx+ny*ny+nz*nz));
 if(n==0) col2=1;
 h=acos((float)(nx*bx+ny*by+nz*bz)/b/n)-PI/2;
 h=(h<0)? -h : h;
 if((col2=(short)((PI/2-h)*(anzcol-1)*2/PI)+1)>(anzcol-1)) col2=anzcol-1;
 if(col2<=0) col1=1;
}
