#include <intuition/intuition.h>
#include <functions.h>
#include <stdio.h>
#include <math.h>
#define WSX Window->MouseX
#define WSY Window->MouseY
#define MX x=tinx[(int)x];y=tiny[(int)y];
#define p(x) *(woj+licz)=x;licz++;
#define BL {printf("\n\nBlad allokacji !!!");exit(100);}
#define MINX 100
#define MINY 0         /* do modyfikacji przy zmianie */
#define MAXX 410           /* rozdzielczosci */
#define MAXY 230 
 
struct Screen *Screen;
struct Screen *Screen1;
struct Window *Window;
struct Window *Window1;
struct Window *Window2;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct IntuiMessage *IM;
struct TextFont *TF8,*TF9;
void *Mathtrans;

struct TextAttr AFont={
       (UBYTE *)"topaz.font",8,0,FPF_ROMFONT};

struct TextAttr BFont={
       (UBYTE *)"topaz.font",9,0,FPF_ROMFONT};

struct NewScreen ekran={
       0,0,320,256,2,0,1,0,WBENCHSCREEN,&AFont,
       (UBYTE *)" ",0,0};

struct NewScreen ekran1={
       0,0,640,256,2,0,1,HIRES,WBENCHSCREEN,&AFont,
       (UBYTE *)" ",0,0};

struct NewWindow okno={
       0,1,320,255,0,1,
       CLOSEWINDOW|MOUSEBUTTONS,
       ACTIVATE|BORDERLESS|WINDOWCLOSE|GIMMEZEROZERO|
       WINDOWDEPTH|RMBTRAP,0,0,
       (UBYTE *)" ",0,0,100,100,
       320,255,CUSTOMSCREEN};

struct NewWindow okno1={
       0,1,640,255,0,1,
       CLOSEWINDOW|MOUSEBUTTONS|VANILLAKEY,
       ACTIVATE|BORDERLESS|GIMMEZEROZERO|WINDOWCLOSE|
       WINDOWDEPTH|RMBTRAP,0,0,
       (UBYTE *)" ",0,0,100,100,
       640,255,CUSTOMSCREEN};

struct NewWindow okno2={
       140,88,360,80,0,1,
       CLOSEWINDOW|MOUSEBUTTONS,
       ACTIVATE|GIMMEZEROZERO|WINDOWCLOSE|
       WINDOWDRAG|WINDOWDEPTH|RMBTRAP,
       0,0,(UBYTE *)"",0,0,50,50,
       360,80,WBENCHSCREEN};
 
char pierwszy=0, kolor=0, blad=0, koniec1=0;
unsigned char *s;
int x1,y1;
double (*fp)();
ULONG Class;
USHORT Code;
double minx,miny,*tinx,*tiny,f6x1,f6y1,f8x1,f8y1;
int w,l;

USHORT getch()
 {
  while (1)
   {
    wait(1<<Window1->UserPort->mp_SigBit);
    while (IM=(struct IntuiMessage *)
            GetMsg(Window1->UserPort))
     {
      Class=IM->Class;
      Code=IM->Code;
      ReplyMsg((struct Message *)IM);
      if (Class==VANILLAKEY) return(Code);
      if (Class==CLOSEWINDOW) {koniec1=1;return(0);}
     }
   }
 }

void czyt(int x, int y, int LEN)
 {
  USHORT c,i=0;
  SetAPen(Window1->RPort,2);
  SetBPen(Window1->RPort,2);
  RectFill(Window1->RPort,x-2,y-l-2,x+w*LEN+2,y+2);
  while ((c=getch())!=13)
   {
    if(c==0) return;
    switch (c)
     {
      case  8 : if (i==0) break;
                i--;
                s[i]='\0';
                SetAPen(Window1->RPort,2);
                RectFill(Window1->RPort,x,y-l,x+w*(i+2)-6,y+2);
                Move(Window1->RPort,x,y);
                SetAPen(Window1->RPort,1);
                Text(Window1->RPort,(char *)s,strlen(s));
                break;
      default : if (i>=LEN) break;
                Move(Window1->RPort,x,y);
                s[i++]=c;
                s[i]='\0';
                SetAPen(Window1->RPort,1);
                Text(Window1->RPort,(char *)s,strlen(s));
                break;
     }
   }
  SetBPen(Window1->RPort,0);
 }

void ramka()
  {
   SetAPen(Window1->RPort,3);
   RectFill(Window1->RPort,430,90,615,92);
   RectFill(Window1->RPort,612,92,615,140);
   RectFill(Window1->RPort,430,138,615,140);
   RectFill(Window1->RPort,430,90,433,140);
  }

void clear()
  {
   SetAPen(Window1->RPort,0);
   RectFill(Window1->RPort,435,95,611,136);
   SetAPen(Window1->RPort,1);
  }

void czolowka()
  {
   Move(Window1->RPort,5,10);
   SetAPen(Window1->RPort,1);
   Text(Window1->RPort,(char *)"Program rysuje wykresy nizej podanych funkcji.",46);
   Move(Window1->RPort,5,10+w+2);
   Text(Window1->RPort,(char *)"W nawiasach podane sa zalecane wartosci parametrÓw.",51);
   Move(Window1->RPort,5,10+2*(w+2));
   Text(Window1->RPort,(char *)"Uwaga: Parametry musza byc liczbami calkowitymi.",48);
   Move(Window1->RPort,20,5+4*(w+4));
   Text(Window1->RPort,(char *)"a. SQRT(SIN(x²+y²))           (130,50,2)",40);    
   Move(Window1->RPort,20,5+5*(w+4));
   Text(Window1->RPort,(char *)"b. SIN(x)+sin(y)                (0,0,2)",39);
   Move(Window1->RPort,20,5+6*(w+4));
   Text(Window1->RPort,(char *)"c. EXP(-x²)-EXP(-y²)            (8,4,2)",39);
   Move(Window1->RPort,20,5+7*(w+4));
   Text(Window1->RPort,(char *)"d. EXP(-x²-y²)                  (9,4,2)",39);
   Move(Window1->RPort,20,5+8*(w+4));
   Text(Window1->RPort,(char *)"e. EXP(-x²)+EXP(-y²)            (8,4,2)",39);
   Move(Window1->RPort,20,5+9*(w+4));
   Text(Window1->RPort,(char *)"f. SIN(x*y)/(x*y)               (9,4,2)",39);
   Move(Window1->RPort,20,5+10*(w+4));
   Text(Window1->RPort,(char *)"g. SIN(x²+y²)/(x²+y²)           (8,4,2)",39);
   Move(Window1->RPort,20,5+11*(w+4));
   Text(Window1->RPort,(char *)"h. SIN(x)/x+SIN(y)/y           (25,15,2)",40);
   Move(Window1->RPort,20,5+12*(w+4));
   Text(Window1->RPort,(char *)"i. SQRT(1-x²-y²)                (4,2,2)",39);
   Move(Window1->RPort,20,5+13*(w+4));
   Text(Window1->RPort,(char *)"j. SIN(x²+y²)/(x²+y²)+EXP(-y²)  (9,4,2)",39);
   Move(Window1->RPort,20,5+14*(w+4));
   Text(Window1->RPort,(char *)"k. SIN(EXP(y²-x²))/EXP(y²+x²)   (8,4,2)",39);
   Move(Window1->RPort,20,5+15*(w+4));
   Text(Window1->RPort,(char *)"l. -x*SIN(y)/y                 (8,12,2)",39);
   Move(Window1->RPort,20,5+16*(w+4));
   Text(Window1->RPort,(char *)"m. -SIN(x*y)/x                 (27,4,2)",39);
   Move(Window1->RPort,20,5+17*(w+4));
   Text(Window1->RPort,(char *)"n. INT(x²+y²)                   (2,4,3)",39);
   Move(Window1->RPort,5,7+19*(w+4)-4);
   Text(Window1->RPort,(char *)"Po zakonczeniu rysowania (migniecie ekranu) powrÓt nastepuje",60);
   Move(Window1->RPort,5,7+20*(w+4)-5);
   Text(Window1->RPort,(char *)"poprzez zamkniecie okna.",24);
   ramka();
  }
 
int zamiana(unsigned char *s,int dl) /* zamienia string cyfr na liczbe */
  {
    unsigned char *pom;
    int d=1,liczba=0,i,a=0;
    pom=s+dl-1;
    if(*s==45) { d=-1; a=1; }
    for(i=dl-1;i>=a;i--)
     {
      liczba+=((*pom)-48)*d;
      d*=10;
      pom--;
     }
    return(liczba);
  }

unsigned char cinput(int x, int y, int LEN)     /* wczytuje znak */
  {
   czyt(x, y, LEN);
   if(koniec1) return(0);
   if(strlen(s)!=1)
    {
     blad=1;
     DisplayBeep(Screen);
     return(0);
    }
   blad=0;
   return(*s);
  }

int iinput(x, y, LEN)    /* wczytuje integer */
  {
   int dl,k;
   czyt(x, y, LEN);
   if(koniec1) return(0);
   dl=strlen(s);
   if((*s!=45)&&((*s>57)||(*s<48)))
     {
      blad=1;
      DisplayBeep(Screen);
      return(0);
     }
   for(k=1;k<dl;k++)
     if((*(s+k)>57)||(*(s+k)<48))
      {
       blad=1;
       DisplayBeep(Screen);
       return(0);
      }
   blad=0;
   return(zamiana(s,dl));
  }
 
double f1(x,y) /* z=sin(sqrt(x^2+y^2)) */
       double x; double y;
  { 
    MX     /* x1=130 y1=50 */
    return(-20*sin(0.43*sqrt(x*x+y*y))); 
  }

double f2(x,y)     /* z=sin(x)*sin(y) */
       double x; double y;
  {
    MX   /* x1=y1=0 */
    return(-70*sin(x)*sin(y));
  } 

double f3(x,y)   /* z=exp(-x*x)-exp(-y*y) */
       double x; double y;
  {
    MX /* x1=8 y1=4 */
    return(-40*(exp(-x*x)+exp(-y*y)));
  }

double f4(x,y)   /* z=exp(-x*x-y*y) */
       double x; double y;
  {
    MX  /* x1=9 y1=4 */
    return(-90*exp(-x*x-y*y));
  }

double f5(x,y)     /* z=exp(-x*x)+exp(-y*y) */
       double x; double y;
  {
    MX  /* x1=9 y1=4 */
    return(-60*(exp(-x*x)-exp(-y*y)));
  }

double f6(x,y) /* z=sin(x*y)/(x*y) */
       double x; double y;
  { 
    double a;
    if(x==f6x1) x--;  /* dzielenie przez zero ! */
    if(y==f6y1) y--;
    MX                 /* x1=9 y1=4 */
    a=x*y;
    return(-40*sin(a)/a);
  } 

double f7(x,y) /* z=sin(x*x+y*y)/(x*x+y*y) */
       double x; double y;
  {
    double a;
    if((x==f6x1)&&(y==f6y1)) y--;
    MX                /* x1=8 y1=4 */ 
    a=x*x+y*y;
    return(-80*sin(a)/a);
  }

double f8(x,y) /* z=sin(x)/x+sin(y)/y */
       double x; double y;
  {
    if(x==f8x1) x--;
    if(y==f8y1) y--;
    MX  /* x1=25 y1=15 */
    return(-60*(sin(x)/x+sin(y)/y));
  }

double f9(x,y) /* z=sqrt(1-x*x-y*y) */
       double x; double y;
  { 
    double z;
    MX  /* x1=4 y1=2 */
    z=1-x*x-y*y;
    if(z>=0) { pierwszy=1; kolor=0; return(-90*sqrt(z)); }
    if(!pierwszy) kolor=1;
    pierwszy=0;
    return(0);
  }
    
double f10(x,y) /* z=sin(x^2+y^2)/(x^2+y^2)+exp(-y*y) */
       double x; double y;
  {
    double a;
    if((x==f6x1)&&(y==f6y1)) y--;
    MX /*x1=9 y1=4 */
    a=x*x+y*y;
    return(-65*(sin(a)/a+exp(-y*y)));
  }

double f11(x,y) /* z=sin(exp(y*y-x*x))/exp(x*x+y*y) */
       double x; double y;
  {
    double a,b;
    MX /* x1=8 y1=4 */
    a=x*x; b=y*y;
    return(-120*(sin(exp(b-a))/exp(a+b)));
  }

double f12(x,y) /* z=-x*sin(y)/y */
       double x; double y;
  {
    if(y==f8y1) y--;
    MX /* x1=8 y1=12 */
    return(-40*-x*sin(y)/y);
  }

double f13(x,y) /* z=-sin(x*y)/x */
       double x; double y;
  {
    if(x==f8x1) x--;
    MX /* x1=27 y1=4 */
    return(-20*-sin(x*y)/x);
  }

double f14(x,y) /* z=floor(x*x+z*z) */
       double x; double y;
  {
    MX /* x1=2 y1=3 */
    return(-15*floor(x*x+y*y-3));
  }   
   
main()
 {
  register int X,Y;
  int n,zas,d,a,*wys1,*wys2,staryx,staryy;
  unsigned char c,mz,licz=30;
  char m,*nam,*woj;
  double q,p,z,*pom2;
  koniec1=0;
  Mathtrans=(void *)OldOpenLibrary("mathtrans.library");
if(!Mathtrans)
{
IntuitionBase=(struct IntuitionBase *)
OldOpenLibrary("intuition.library");
if(!IntuitionBase) exit(100);
GfxBase=(struct GfxBase *)OldOpenLibrary("graphics.library");
if(!GfxBase) exit(100);
okno2.Screen=0;
if(!(Window2=OpenWindow(&okno2))) {koniec1=1; goto koniec;}
TF9=OpenFont(&BFont);
SetFont(Window2->RPort,TF9);
SetAPen(Window2->RPort,1);
Move(Window2->RPort,11,12);
Text(Window2->RPort,(char *)
"Program wymaga obecnosci na dysku",33);
Move(Window2->RPort,11,26);
Text(Window2->RPort,(char *)"        mathtrans.library.",26);
Move(Window2->RPort,11,40);
Text(Window2->RPort,(char *)
" Znajduje sie ona na Workbench'u",32);
Move(Window2->RPort,11,54);
Text(Window2->RPort,(char *)"         w katalogu libs.",25);
blad=1;
while(blad)
 {
  Wait(1<<Window2->UserPort->mp_SigBit);
  while(IM=(struct IntuiMessage *)GetMsg(Window2->UserPort))
   {
    Class=IM->Class;
    ReplyMsg((struct Message *)IM);
    if(Class==CLOSEWINDOW) {blad=0;break;}
   }
 }
CloseWindow(Window2);
CloseFont(TF9);
if(IntuitionBase) CloseLibrary(IntuitionBase);
if(GfxBase) CloseLibrary(GfxBase);
exit(0);
}
  IntuitionBase=(struct IntuitionBase *)
    OldOpenLibrary("intuition.library");
  if(!IntuitionBase) exit(100);
  GfxBase=(struct GfxBase *)
    OldOpenLibrary("graphics.library");
  if(!GfxBase) exit(100);
  s=(unsigned char *)malloc(100);
  if(!s) BL
  tinx=(double *)malloc(641*sizeof(double)); /*jak by bylo cos*/
  if(!tinx) BL                               /*z pamiecia, to */
  tiny=(double *)malloc(641*sizeof(double)); /*tu mozna troche*/
  if(!tiny) BL                               /*  oszczedzic.  */
  pom2=(double *)malloc(641*sizeof(double));
  if(!pom2) BL
  wys1=(int *)malloc(641*sizeof(int));
  if(!wys1) BL
  wys2=(int *)malloc(641*sizeof(int));
  if(!wys2) BL
  nam=(char *)malloc(40);
  if(!nam) BL
  woj=(char *)malloc(80);
  if(!woj) BL
  woj=(char *)"Grafika Przestrzenna v 2.0  W Wojciech Zuchowski  28-03-1992 Warszawa ";
  *(woj+28)=169;p(87)p(111)p(106)p(99)p(105)p(101)p(99)p(104)
  licz++;p(90)p(117)p(99)p(104)p(111)p(119)p(115)p(107)p(105)
  if(!(Screen1=OpenScreen(&ekran1))) {koniec1=1; goto koniec;}
  SetRGB4(&Screen1->ViewPort,0L,2,3,2);
  SetRGB4(&Screen1->ViewPort,1L,13,13,13);
  SetRGB4(&Screen1->ViewPort,2L,6,6,0);
  SetRGB4(&Screen1->ViewPort,3L,0,14,0);
  okno1.Screen=Screen1;
  okno1.Title=(UBYTE *)woj;
  if(!(Window1=OpenWindow(&okno1))) {koniec1=1; goto koniec;}
  TF8=OpenFont(&AFont);
  SetFont(Window1->RPort,TF8); 
  w=Window1->RPort->TxHeight;
  l=Window1->RPort->TxBaseline;
do
 {  
  czolowka();
  do
   {
    clear();
    SetAPen(Window1->RPort,1);
    Move(Window1->RPort,440,103);
    Text(Window1->RPort,(char *)"Wybierz funkcje (a-n)",21);
    Move(Window1->RPort,440,103+w+2);
    Text(Window1->RPort,(char *)"  albo zamknij okno",19); 
    switch(c=cinput(500,128,1))
     {
case 97 : fp=f1;minx=2;miny=2;
          nam="         SIN(SQRT(x²+y²))         ";break;
case 98 : fp=f2;minx=25;miny=25;
          nam="          SIN(x)+SIN(y)           ";break;
case 99 : fp=f3;minx=30;miny=30;
          nam="        EXP(-x²)-EXP(-y²)         ";break;
case 100 : fp=f4;minx=30;miny=30;
           nam="           EXP(-x²-y²)            ";break;
case 101 : fp=f5;minx=30;miny=30;
           nam="        EXP(-x²)+EXP(-y²)         ";break;
case 102 : fp=f6;minx=30;miny=30;
           nam="          SIN(x*y)/(x*y)          ";break;
case 103 : fp=f7;minx=30;miny=30;
           nam="        SIN(x²+y²)/(x²+y²)        ";break;
case 104 : fp=f8;minx=10;miny=10;
           nam="        SIN(x)/x+SIN(y)/y         ";break;
case 105 : fp=f9;minx=70;miny=70;
           nam="          SQRT(1-x²-y²)           ";break;
case 106 : fp=f10;minx=30;miny=30;
           nam="   SIN(x²+y²)/(x²+y²)+EXP(-y²)    ";break;
case 107 : fp=f11;minx=30;miny=30;
           nam="    SIN(EXP(y²-x²))/EXP(y²+x²)    ";break;
case 108 : fp=f12;minx=30;miny=10;
           nam="           -x*SIN(y)/y            ";break;
case 109 : fp=f13;minx=10;miny=30;
           nam="           -SIN(x*y)/x            ";break;
case 110 : fp=f14;minx=60;miny=40;
           nam="            INT(x²+y²)            ";break;
case   0 : koniec1=1; goto koniec;
      default  : break;
     }
    if(!(((c<=110)&&(c>=97)))) {blad=1;DisplayBeep(Screen1);}
   }
  while(blad);
  do
   {
    clear();
    Move(Window1->RPort,440,103);
    Text(Window1->RPort,(char *)"Podaj przesuniecie x",20);
    x1=iinput(500,128,5);
    if(koniec1) goto koniec;
   }
  while(blad);
  do
   {
    clear();
    Move(Window1->RPort,440,103);
    Text(Window1->RPort,(char *)"Podaj przesuniecie y",20);
    y1=iinput(500,128,5);
    if(koniec1) goto koniec;
   }
  while(blad);
  do
   {
    clear();
    Move(Window1->RPort,440,103);
    Text(Window1->RPort,(char *)"Podaj kat nachylenia",20);
    Move(Window1->RPort,440,103+w+2);
    Text(Window1->RPort,(char *)"        (1-5)",13);
    a=iinput(500,128,1);
    if(koniec1) goto koniec;
    if((a<1)||(a>5)) DisplayBeep(Screen1);
   }
  while((blad)||(a<1)||(a>5));
  do
   {
    clear();
    Move(Window1->RPort,440,103);
    Text(Window1->RPort,(char *)" Czy wykres ma byc",18);
    Move(Window1->RPort,440,103+w+2);
    Text(Window1->RPort,(char *)"\"odwrocony\" (t/n) ?",19);
    mz=cinput(500,128,1);
    if(koniec1) goto koniec;
    if((mz!='t')&&(mz!='n')) DisplayBeep(Screen1);
   }
  while((blad)||((mz!='t')&&(mz!='n')));
  if(mz=='t') m=-1;
  else m=1;
  if(!(Screen=OpenScreen(&ekran))) { koniec1=1; goto koniec; }
  SetRGB4(&Screen->ViewPort,0L,0,0,0);
  SetRGB4(&Screen->ViewPort,1L,14,14,14);
  SetRGB4(&Screen->ViewPort,2L,7,4,0);
  SetRGB4(&Screen->ViewPort,3L,0,15,0);
  okno.Screen=Screen;
  okno.Title=(UBYTE *)nam;
  if(!(Window=OpenWindow(&okno))) { koniec1=1; goto koniec; }
          /* czesc rysujaca */
    for(X=0;X<=641;X++)              /* "pom z lewj" */    
     {                          /* 220/a - kat nachylenia  */  
      wys1[X]=1000;             /* 150-150/a - niwelowanie */
      wys2[X]=-1000;            /* efektu podjezdzania do  */
     }                          /* gory przy zwiekszaniu   */ 
                                /* kata nachylenia wykresu */
    for(X=MINY;X<=MAXY;X++) pom2[X]=((double)X-150)/a+150;
    for(X=MINX;X<=MAXX;X++) tinx[X]=X/minx-x1;
    for(Y=MINY;Y<=MAXY;Y++)   tiny[Y]=Y/miny-y1;
    f6x1=(double)x1*30;
    f6y1=(double)y1*30;
    f8x1=(double)x1*10;        /* do optymalizacji */
    f8y1=(double)y1*10;
    pierwszy=kolor=blad=0;
    for(X=MINX;X<=MAXX;X+=2)  
     {
      q=(double)X;   
      p=MAXY;        /* 230 dwie linie w dol*/ 
      d=(int)(pom2[MAXY]+m*(*fp)(q,p));
      Move(Window->RPort,X,d);
      staryx=X;staryy=w;
      d=X+1;
      for(Y=MAXY;Y>=MINY;Y--)
       {
        d--;          /* plaszczyzna */
        q=(double)X;             /* rozciagniecie wykresu */
        p=(double)Y;
        zas=(int)(pom2[Y]+m*(*fp)(q,p));
/*!!!*/ if((zas<=0) || (zas>=255) || (d<=0) || (d>=319)) c=1;
        else
         {
          if(zas<wys1[d]) 
           {
            if((staryy>wys1[d])&&(wys1[staryx]!=1000))
               Move(Window->RPort,staryx,wys1[staryx]); 
            if(kolor) SetAPen(Window->RPort,2);
            else SetAPen(Window->RPort,1);
            c=0;
            wys1[d]=zas;
            Draw(Window->RPort,d,zas);
           } 
          else c=1;
          if(zas>wys2[d])
           {
            if((staryy<wys2[d])&&(wys2[staryx]!=-1000))
               Move(Window->RPort,staryx,wys2[staryx]);
            SetAPen(Window->RPort,3);
            c=0;
            wys2[d]=zas;
            Draw(Window->RPort,d,zas);
           }
          else c=1;
         } 
        if(c)  Move(Window->RPort,d,zas);
        staryx=d;staryy=zas;
       }
     }
   Delay(25);
   DisplayBeep(Screen);Delay(10);
   DisplayBeep(Screen);Delay(10);
   DisplayBeep(Screen);Delay(10);
   blad=1;
   while (blad)
   {
     Wait (1<<Window->UserPort->mp_SigBit);
     while (IM=(struct IntuiMessage *)GetMsg(Window->UserPort))
     {
       Class=IM->Class;
       Code=IM->Code;
       ReplyMsg((struct Message *)IM);
       if (Class==CLOSEWINDOW) {blad=0; break;}
     }
   }
   if(Window) {CloseWindow(Window);Window=NULL;}
   if(Screen) {CloseScreen(Screen);Screen=NULL;}
}
while(1);           
   koniec:
 CloseFont(TF8);              /* zamkniecie okna i ekranu */
 if(koniec1)
  {
   if(Window) CloseWindow(Window);
   if(Screen) CloseScreen(Screen);
   if(Window1) CloseWindow(Window1);
   if(Screen1) CloseScreen(Screen1);
  }
   if(IntuitionBase) CloseLibrary(IntuitionBase);
   if(GfxBase) CloseLibrary(GfxBase);
   if(Mathtrans) CloseLibrary(Mathtrans);
   free(nam);free(s);free(tinx);free(tiny);
   free(woj);free(pom2);free(wys1);free(wys2); 
   exit(0);
 } 
