/* EARTH-BOING V1.4 ....
 * von Tim Pietzcker Software
 * --------------------------
 * Diese Version fertiggestellt :
 * 29.August 1988
 * Änderungen seit 1.3 :
 * Geschwindigkeitssteigerung beim Füllen
 */

#include <intuition/intuition.h>   /* Manager */
#include <graphics/gfxbase.h>      /* Designer */
#include <graphics/gfxmacros.h>    /* Special Effects */
#include <math.h>                  /* Clapper Holder */
#include <exec/types.h>            /* Casting */
#define PI180 0.017453292   /* pi durch 180 */
#ifndef MAXBILDER
#define MAXBILDER 72          /* Anzahl der Einzelbilder für die Animation.
                                 Kann,muß aber nicht beim Compilieren
                                 angegeben werden,und zwar so :
                                    cc -DMAXBILDER=n Earth-Boing
                                 ,wobei für n die gewünschte Anzahl
                                 eingesetzt werden muß.
                                 Mögliche Werte: Teiler von 360.
                                 Sinnvolle Werte : 36 und 72 (bei mehr
                                 dauert das Rechnen zu lange,und es wird
                                 mehr Speicher verbraucht; bei weniger
                                 wird die Animation zu ruckhaft */
#endif

struct IntuitionBase *IntuitionBase;   /* als Adresse von Intuition */
struct GfxBase       *GfxBase;         /*  "     "     "  Graphics */
struct Library       *OpenLibrary();   /* ich deklariere die Funktions-
                                          aufrufe,die keinen 16-bit int
                                          zurückgeben,damit ich das
                                          Programm mit 16-bit ints
                                          compilieren kann (sonst Guru !!)*/
struct Window        *MyWindow,*OpenWindow();  /* Zeiger auf Window; s.o. */
struct Window        *mw[2];           /* aufgrund des Double-Buffering
                                          brauche ich zwei Windows während
                                          der Animation */
struct Screen        *ms[2],*OpenScreen();   /* siehe oben */
struct RastPort      *rp[2];           /* s.o. */
struct ViewPort      *vp[2];           /* s.o. */
struct IntuiMessage  *msg,*GetMsg();   /* Zeiger auf Message */
struct BitMap        myBM[MAXBILDER],*MyWindowBM[2]; /* Bitmaps,Pointers */
PLANEPTR             AllocRaster(),myplane;
struct TmpRas        hilfras,*InitTmpRas();

struct NewWindow TheWindow =           /* jetzt die Daten für das Window,
                                          in dem die Einzelbilder vorge-
                                          zeichnet werden */
{
   0,0,           /* links oben */
   212,115,          /* Breite,Höhe */
   0,1,              /* Detail-, BlockPen */
   NULL,             /* IDCMP-Flags */
   GIMMEZEROZERO|ACTIVATE,
                     /* Flags */
   NULL,NULL,        /* FirstGadget,CheckMark */
   (UBYTE *)"Please wait a second...", /* Titel */
   NULL,             /* kommt noch */
   NULL,             /* keine selbstgebaute BitMap */
   0,0,0,0,          /* kein Sizing */
   CUSTOMSCREEN,     /* Typ */
};                   /* Semikolon DARF nicht vergessen werden !! */

struct NewWindow TheWindow2 =          /* die Animations-Window-Daten */
{
   0,0,
   640,200,
   0,1,
   MOUSEBUTTONS,
   GIMMEZEROZERO,
   NULL,NULL,
   NULL,
   NULL,NULL,
   0,0,0,0,
   CUSTOMSCREEN,
};

struct NewScreen TheScreen =           /* für die zwei neuen Screens */
{
   0,0,
   640,200,
   1,0,1,
   HIRES,
   CUSTOMSCREEN,
   NULL,
   (UBYTE *)"                           EARTH-BOING © 1988 by Tim Pietzcker",
   NULL,
   NULL,
};

/* jetzt kommt die Initialisierung der globalen Variablen (keine Lust auf
 * call by reference) 
 */

double sin(),cos();
int drehung=0,winkel,laenge,breite;
float x,y,z=0,za;
double sn[361],cs[361]; /* Da der Amiga am liebsten so wenig wie möglich
                         * rechnet,berechne ich die sinüsse und cosinüsse
                         * im voraus (siehe weiter unten) */
int datanz[] = { 0,31,37,5,34,20,5,11,5,4,56,3,3,7,4,4,10,117,4,4,4,6,3 };
             /* Anzahl der Punkte,die die Kontinente und Inseln besitzen */

/* jetzt kommt der große Brocken - sämtliche Umrißpunktdaten (jeweils als
 * Pärchen - Längengrad und Breitengrad
 */
               /* Südamerika */
int erddat[] ={0,-70,12,-61,10,-56,6,-52,5,-50,0,-40,-4,-36,-6,
               -35,-9,-39,-15,-41,-22,-48,-26,-49,-29,
               -55,-35,-57,-35,-58,-39,-61,-39,-68,-47,
               -66,-48,-70,-51,-63,-55,-70,-56,-75,-53,
               -76,-49,-74,-37,-72,-30,-70,-18,-76,-14,
               -81,-6,-80,0,-77,7,-75,11,-70,12,
               /* Afrika */
               -6,35,2,36,10,37,10,33,20,31,21,33,32,32,
               36,20,44,11,51,12,50,8,47,3,39,-4,41,-14,
               35,-19,35,-24,33,-26,31,-30,26,-34,19,-34,
               17,-28,15,-23,12,-18,14,-11,13,-5,9,-1,10,4,
               6,4,4,6,-2,5,-8,5,-12,8,-17,15,-16,21,-12,28,
               -10,30,-9,32,-6,35,
               /* Madagaskar */
               49,-12,51,-15,47,-25,43,-25,44,-15,49,-12,
               /* Antarktis */
               -180,-89,-180,-85,-155,-86,-159,-77,-122,-72,
               -100,-74,-100,-72,-75,-73,-70,-66,-55,-63,
               -65,-68,-60,-73,-70,-80,-35,-80,-35,-77,-20,-72,
               0,-70,20,-70,40,-69,53,-66,70,-67,70,-70,
               80,-68,85,-66,100,-66,115,-65,120,-66,135,-65,
               150,-68,166,-70,170,-72,162,-75,160,-82,
               180,-85,180,-89,
               /* Australien */
               142,-11,148,-20,153,-25,153,-32,150,-38,140,-38,
               134,-32,126,-32,119,-34,116,-33,115,-30,114,-25,
               115,-22,121,-20,127,-14,130,-15,130,-11,136,-11,
               135,-15,141,-18,142,-11,
               /* Neuseeland */
               173,-35,178,-38,170,-47,167,-46,
               175,-37,173,-35,
               /* Neuguinea */
               130,0,134,0,136,-2,138,-1,146,-5,150,-10,145,-8,
               143,-10,138,-8,138,-4,132,-3,130,0,
               /* Borneo */
               117,7,119,5,116,-4,110,-4,109,2,117,7,
               /* Sumatra */
               98,5,105,-3,104,-6,95,5,98,5,
               /* Nordamerika */
               -80,25,-81,25,-83,30,-95,30,-98,27,-98,22,
               -95,19,-90,21,-87,21,-89,16,-84,15,-84,10,
               -75,10,-85,10,-95,17,-105,20,-112,32,-117,32,
               -110,23,-117,34,-120,32,-125,40,-125,48,
               -130,54,-140,60,-150,60,-165,55,-158,58,
               -165,62,-160,64,-166,64,-166,66,-160,66,
               -166,68,-156,72,-135,69,-127,70,-110,68,
               -81,70,-81,66,-95,62,-92,57,-83,55,-83,52,
               -79,52,-79,55,-77,57,-78,63,-70,58,-65,60,
               -56,52,-65,50,-62,45,-75,42,-76,36,-81,32,-80,25,
               /* Neufundland */
               -53,47,-59,48,-56,52,-53,47,
               /* Kuba */
               -85,22,-82,23,-75,21,-85,22,
               /* Baffin */
               -66,63,-77,65,-72,68,-89,70,-90,73,-79,73,
               -62,66,-66,63,
               /* Victoria */
               -101,70,-115,70,-120,73,-105,74,-101,70,
               /* Ellismere */
               -80,76,-90,76,-95,82,-70,83,-80,76,
               /* Grönland */
               -45,60,-50,62,-55,70,-60,76,-60,76,-70,78,-40,85,
               -20,80,-22,70,-40,65,-45,60,
               /* Eurasien */
               76,8,72,21,70,20,66,25,55,26,50,30,48,28,
               52,24,56,26,60,22,57,19,52,16,44,12,41,20,
               33,32,34,32,36,37,27,36,27,42,42,42,38,47,
               30,46,29,42,22,40,25,38,22,36,20,40,20,42,
               13,46,12,44,17,40,15,37,12,38,17,39,10,44,
               7,43,3,43,3,41,0,40,0,38,-2,37,-6,36,-7,37,
               -9,37,-9,43,-2,43,-2,46,-4,48,9,54,8,57,
               10,58,14,54,21,55,25,66,21,65,18,62,16,56,
               12,55,10,60,5,57,5,63,20,70,25,71,43,67,
               65,70,70,73,80,72,80,74,105,78,112,76,113,74,
               130,73,130,71,150,72,160,70,175,70,170,66,
               180,65,180,63,170,60,162,60,162,56,157,52,
               156,58,160,60,157,62,155,59,141,59,136,55,
               141,45,140,47,134,43,128,39,129,35,126,35,
               125,40,118,39,121,31,120,26,116,23,109,21,
               105,19,109,16,109,11,105,10,100,14,100,8,
               104,2,100,4,98,8,97,17,94,16,94,20,92,22,
               88,22,80,16,80,10,76,8,
               /* Großbritannien */
               -5,58,-3,58,1,52,-5,50,-5,58,
               /* Irland */
               -7,55,-7,52,-10,52,-10,54,-5,55,
               /* Island */
               -22,67,-15,67,-13,65,-20,64,-22,67,
               /* Japan */
               141,45,145,44,140,35,130,31,130,34,139,38,141,45,
               /* Sri Lanka (Ceylon) */
               80,10,82,8,80,7,80,10
   };

int fuelldat[] =              /* Falls der Benutzer die Erdteile als aus-
                                 gefüllte Flächen haben will,wird an den
                                 hier angegebenen Koordinaten ein Füll-
                                 versuch vorgenommen. Da selten ein ganzer
                                 Kontinent auf einmal sichtbar ist,brauche
                                 ich mehrere Füllpunkte pro Erdteil */
{  0,-78,0,-45,-10,-70,-40,   /* Südamerika */
   -10,20,25,-30,40,5,30,25,  /* Afrika */
   46,-20,                    /* Madagaskar */
   0,-75,90,-70,140,-75,-110,-80,   /* Antarktis */
   120,-30,150,-30,133,-15,145,-35, /* Australien */
   176,-39,                   /* Neuseeland */
   141,-7,                    /* Neuguinea */
   115,0,                    /* Borneo */
   -150,65,-70,54,-102,25,-100,40,  /* Nordamerika */
   -45,65,-40,75,             /* Grönland */
   -5,40,20,50,80,20,100,20,160,65,100,70,   /* Eurasien */
   -2,52,                     /* Großbritannien */
   135,35,                    /* Japan */
   -70,65,-80,72,             /* Baffin */
   -109,71,                   /* Victoria */
   -80,80,                    /* Ellismere */
};

init()                        /* um keine Zeit mit den andauernden trans-
                                 zendentalen Rechenoperationen zu ver-
                                 schwenden */
{
   int sch;
   printf("Ich initialisiere die Sinus-Cosinus-Tabelle....\n");
   for(sch=0;sch<361;sch++)
   {
      sn[sch] = sin ( ( (double) sch) * PI180);
      cs[sch] = cos ( ( (double) sch) * PI180);
   }
}

aufmachen()                   /* Libraries,Screens öffnen */
{
   int i;

   if ((IntuitionBase = (struct IntuitionBase *)
      OpenLibrary("intuition.library",0l))==NULL)
      printf("Wo ist denn dieses #!?@§ Intuition ?!!\n"),exit(FALSE);

   if ((GfxBase =(struct GfxBase *)
      OpenLibrary("graphics.library",0l))==NULL)
      printf("Wer hat mit meinem Malkasten gemalt ??\n"),exit(FALSE);

   if ((ms[0] = OpenScreen(&TheScreen))==NULL)
      exit (FALSE);

   if ((ms[1] = OpenScreen(&TheScreen))==NULL)
      CloseScreen(ms[0]),exit(FALSE);

   ScreenToBack(ms[0]),ScreenToBack(ms[1]);

   for (i=0;i<2;i++)
   {
      vp[i]=&(ms[i]->ViewPort);
      SetRGB4(vp[i],0l,0l,0l,0l);
      SetRGB4(vp[i],1l,15l,15l,15l);
   }
}

berechne(l,b)  /* Dies ist die eigentliche Rechenroutine */
int l,b;       /* Werte brauchen nicht zurückgegeben werden */
{
float v,t;
   l=l-drehung;            /* eingestellter Drehwinkel */
   if (l>359) l %=360;     /* Rückführen der Werte in  */
   while (l<0) l +=360;    /* den Bereich 0 bis 359    */
   while (b<0) b +=360;
   x=sn[l]*cs[b];          /* sn für sinus;cs für cosinus */
   v=cs[l]*cs[b];
   t=sn[b];
   y=t*cs[winkel]-v*sn[winkel];
   za=z;
   z=t*sn[winkel]+v*cs[winkel];
}

allocate_bitmaps()         /* sämtliche Einzelbilder werden in lauter */
{                          /* Mini-BitMaps gespeichert (immerhin belegt */
   int i,j;                /* eins schon 2.5 KByte,72 Bitmaps also 180KB)! */
                           /* Diese BitMaps werden hier alloquiert und */
   for(j=0;j<MAXBILDER;j++)/* initialisiert */
   {
      InitBitMap(&myBM[j],1l,201l,101l);
      myBM[j].Planes[0]=AllocRaster(201l,101l);
      if (myBM[j].Planes[0]==NULL)  /* kein Speicher mehr frei */
      {
         abbruch:
         for(i=j-1;i>=0;i--)
         {
            FreeRaster(myBM[i].Planes[0],201l,101l);
         }
         CloseScreen(ms[0]);  /* schön saubermachen */
         CloseScreen(ms[1]);
         exit(FALSE);
      }
   }
   myplane=AllocRaster(212l,115l);
   if (myplane==NULL) goto abbruch;
}

main()
{
   int i,j,schleife,scrsw,fuellen;
   unsigned int zaehler;
   long brl,brt,inc,inc2,weitermachen=TRUE,xpos,ypos,wink,
   minterm=0x00C0,mask=0x00FF;   /* die zwei bestimmen beim BltBitMap'en
                                    die Art des Kopierens.So,wie sie jetzt
                                    eingestellt sind,heißt das :genaue
                                    Kopie */
   float x1,y1;

   aufmachen();
   init();
   allocate_bitmaps();

   do {                 /* Dies ist die Hauptschleife.Sie wird mindestens
                         * einmal ausgeführt und beendet bei Eingabe von
                         * -1 (s.u.).Kontroll-Flag :weitermachen          */
      WBenchToFront();
      printf("%c",12);
      printf("                         EARTH-BOING Version 1.4\n");
      printf("                programmiert in Aztec C von Tim Pietzcker\n");
      printf("\n");
      printf("Bitte gib den Neigungswinkel in Grad ein (0-359,normal 23)\n");
      printf("oder -1 zum Beenden :");
      scanf("%d",&winkel);
      if (winkel>359 || winkel<0) weitermachen=FALSE;
      else weitermachen=TRUE;
      if (weitermachen)    /* sonst Schluß */
      {
         printf("Sollen Flächen ausgefüllt werden (1) oder nicht (0) ?");
         scanf("%d",&fuellen);
         TheWindow.Screen=ms[0];
         ScreenToFront(ms[0]);
         if ((MyWindow=OpenWindow(&TheWindow))==NULL) goto ende;
         rp[0]=MyWindow->RPort;
         rp[0]->TmpRas=InitTmpRas(&hilfras,myplane,(long)RASSIZE(212l,115l));
         MyWindowBM[0]=rp[0]->BitMap;
         SetAPen(rp[0],1l);
         SetOPen(rp[0],1l);
         SetBPen(rp[0],1l);
         brl=MyWindow->BorderLeft;
         brt=MyWindow->BorderTop;

         for(schleife=0;schleife<=MAXBILDER-1;schleife++) /* Einzelbilder */
         {
            SetRast(rp[0],0l);
            drehung=schleife*(360/MAXBILDER);
            for (j=1,zaehler=1;j<23;j++,zaehler++) /* Kontinente/Inseln
                                                      nacheinander */
            {
               laenge=erddat[zaehler];
               breite=erddat[++zaehler];
               berechne(laenge,breite);
               x1=x;
               y1=y;
               zaehler++;
               for (i=1;i<=datanz[j];i++,zaehler++) /* einzelne Punkte */
               {
                  laenge=erddat[zaehler];
                  breite=erddat[++zaehler];
                  berechne(laenge,breite);
                  if (z>=0 && za>=0)      /* Hidden Lines */
                  {
                     Move(rp[0],(long)(100*x1+100),(long)(-50*y1+50));
                     Draw(rp[0],(long)(100*x+100),(long)(-50*y+50));
                  }
                  x1=x;
                  y1=y;
               }
               zaehler--; /* um 1 zu hoch gezählt */
            }
            DrawEllipse(rp[0],100l,50l,100l,50l);
            if (fuellen==1)
            {
               DrawEllipse(rp[0],100l,50l,99l,50l);
               DrawEllipse(rp[0],100l,50l,101l,51l);  /* Dies ist als
                                                         "Auslaufschutz"
                                                         gedacht (hat nichts
                                                         mit PAMPERS zu tun)
                                                      */
               for(i=1;i<=74;i+=2)
               {
                  laenge=fuelldat[i];
                  breite=fuelldat[i+1];
                  berechne(laenge,breite);
                  if (z>0)
                     Flood(rp[0],0l,(long)(100*x+100),(long)(-50*y+50));
               }
               SetAPen(rp[0],0l);

               DrawEllipse(rp[0],100l,50l,101l,51l);
               SetAPen(rp[0],1l);
            }
            BltBitMap(MyWindowBM[0],brl,brt,
             &myBM[schleife],0l,0l,201l,101l,
             minterm,mask,NULL);
            /* So,dieser gigantische Befehl schneidet ein Stück aus der
               BitMap von meinem Window und klebt die Kopie in eine der
               36 Mini-BitMaps */
         }
         CloseWindow(MyWindow);
         /* Jetzt haben wir alle Drehungen in lauter kleinen Bitmaps
            abgelegt und können die nun für unsere Animation verwenden */
         TheWindow2.Screen=ms[0];
         if ((mw[0]=OpenWindow(&TheWindow2))==NULL) goto ende;
         TheWindow2.Screen=ms[1];
         if ((mw[1]=OpenWindow(&TheWindow2))==NULL)
         {
            CloseWindow(mw[0]);
            goto ende;
         }
         rp[0]=mw[0]->RPort;
         MyWindowBM[0]=rp[0]->BitMap;
         rp[1]=mw[1]->RPort;
         MyWindowBM[1]=rp[1]->BitMap;
         inc=4,inc2=3,j=0;
         xpos=0;
         wink=270;
         ypos=86+87*sn[wink];
         scrsw=1;

         while ((msg=GetMsg(mw[0]->UserPort))==NULL) /* weiter,solange noch
                                                        kein Event = Maus-
                                                        klick aufgetreten */
         {
            scrsw=1-scrsw;
            ScreenToFront(ms[scrsw]);        /* Page Flip ! */

            SetRast(rp[1-scrsw],0l);
            xpos+=inc;                       /* Position des nächsten Bildes
                                                berechnen (invertierte nega-
                                                tive Sinuskurve) ...*/
            if (xpos>430 || xpos<0) xpos-=inc,inc=-inc;
            wink+=inc2;
            if (wink>360 || wink<180) wink-=inc2,inc2=-inc2;
            ypos=86+87*sn[wink];
            if (winkel <180) j+=inc/4; else j-=inc/4;
            if (j==MAXBILDER) j=0;
            if (j==-1) j=MAXBILDER-1;
            BltBitMap(&myBM[j],0l,0l,MyWindowBM[1-scrsw],
             xpos+brl,ypos+brt,
             201l,101l,minterm,
             mask,NULL );
            /* ... und die BitMap wieder zurückkopieren ... */

         }
         ReplyMsg(msg);            /* Mausklick-Message beantworten */
         CloseWindow(mw[0]),CloseWindow(mw[1]); /* und aufräumen */
      }

   } while (weitermachen);
   ende:
   if (myplane) FreeRaster(myplane,212l,115l);
   for (i=0;i<MAXBILDER;i++) FreeRaster(myBM[i].Planes[0],201l,101l);
   /* raus mit dem Ballast */
   CloseScreen(ms[0]),CloseScreen(ms[1]);
   CloseLibrary(GfxBase);
   CloseLibrary(IntuitionBase);
}

/* total fertig */
