// g400.c
// compile with:   cc -o g400 g400.c -lgd -lpng -lm
//
// Uses the libgd library.  For documentation see the file:
//   /usr/share/doc/gd-*/index.html  
//
// or the website:
//   http://www.libgd.org/Reference

#define  NAME        "g400"
#define  LABEL0      "Tumbling"
#define  LABEL1      "Max  NLP"
#define  LABEL2      "Min  NLP"
#define  LABEL3      "Zero NLP"
#define  NFRAME      120
#define  XFRAME      1024
#define  YFRAME      300
#define  R00         120
#define  XCENT0      (512-360)
#define  XCENT1      (512-120)
#define  XCENT2      (512+120)
#define  XCENT3      (512+360)
#define  YCENT       160
#define  SATSIZE     30
#define  FSZ         16
#define  FSX         55
#define  FSY         22
#define  FNT         "DejaVuMonoSans"

#include "gd.h"
#include "math.h"
#include <stdio.h>

int main() {
   FILE   *pngout         ;                /* Declare output file */
   char   dirname[80]     ;
   char   framename[80]   ;
   char   cmdstr[80]      ;
   char   pngfile[80]     ;

   int     sun1, white, red, green, blue;  /* Declare color indexes */
   int     gray, dgray, dwhit, dgreen, trans ;
   int     dred, cyan, dcyan ;

   double  pi2    = 8.0 * atan( 1.0 );
   double  dangle = pi2 / ((double)NFRAME );
   double  rad    = pi2/360.0       ;
   double  satangle                 ;
   double  satdraw                  ;
   double  c, s                     ; // satangle sine and cosine
   double  cx, cy                   ; // orbit center
   double  tx, ty                   ; // back offset x and y
   double  ox, oy                   ; // drawing dot position
   int     dcell    = SATSIZE/2     ;
   int     drand    = 4*SATSIZE/5   ;
   int     sth      = SATSIZE/10    ;
   double  th       = (double) sth  ; // back thickness/offset
   int     derth    = R00           ;
   double  r00      = (double) R00  ;
   int     frame                    ;
   int     centerx, centery         ; // orbit and earth center
   int     oxh, oxl                 ; // edges of the earth

   gdImagePtr         im            ; // Declare the image

   //------------------------------------------------------------
 
   // make directory
   sprintf( cmdstr, "rm -rf %sdir ; mkdir %sdir", NAME, NAME );
   system( cmdstr );

   for( frame=0 ; frame < NFRAME ;  frame++ ) {

      double angle = dangle*((double)frame);
      im           = gdImageCreateTrueColor(XFRAME, YFRAME );

      // Allocate the colors sun1, white, red, green, blue
      white  = gdImageColorAllocate(im, 255, 255, 255);
      sun1   = gdImageColorAllocate(im,  51,  51, 102);
      red    = gdImageColorAllocate(im, 255,   0,   0);
      dred   = gdImageColorAllocate(im,  96,   0,   0);
      green  = gdImageColorAllocate(im,   0, 255,   0);
      dgreen = gdImageColorAllocate(im,   0,  80,   0);
      cyan   = gdImageColorAllocate(im,   0, 255, 255);
      dcyan  = gdImageColorAllocate(im,   0,  96,  96);
      gray   = gdImageColorAllocate(im, 128, 128, 128);
      dwhit  = gdImageColorAllocate(im, 192, 192, 192);
      dgray  = gdImageColorAllocate(im,  48,  48,  48);
      blue   = gdImageColorAllocate(im,   0,   0, 255);
      trans  = gdImageColorAllocate(im, 1, 1, 1);

      // line thickness of 1
      gdImageSetThickness( im, 1 ) ;

      centery  = YCENT          ;

      double satdraw            ;
      double cx = r00*sin(angle);
      double cy = r00*cos(angle);
      double th = (double) sth  ;
      double ox, oy             ;
      double c, s               ;
      double tx, ty             ;

      // random tumble  ----------------------------------------------

      gdImageFilledArc(im, XCENT0,YCENT, derth,derth, 0, 180,  green, gdArc );
      gdImageFilledArc(im, XCENT0,YCENT, derth,derth, 180, 0, dgreen, gdArc );
      gdImageStringFT( im,NULL,white, FNT,FSZ,0.0, XCENT0-FSX, FSY, LABEL0 );
      centerx = XCENT0 ;
      oxh = centerx + 0.5*derth;
      oxl = centerx - 0.5*derth;

      ox  = centerx + ((int)(r00*sin(angle)));
      oy  = centery + ((int)(r00*cos(angle)));

      if( ( ox > oxh ) || ( ox < oxl ) || ( oy > centery ) ) {
         gdImageFilledArc(im, ox, oy, drand, drand, 0, 360, dwhit  , gdArc);
      } else {
         gdImageFilledArc(im, ox, oy, drand, drand, 0, 360, gray   , gdArc);
      }

      // max nightlight -----------------------------------------------

      gdImageFilledArc(im, XCENT1,YCENT, derth,derth, 0, 180,  green, gdArc );
      gdImageFilledArc(im, XCENT1,YCENT, derth,derth, 180, 0, dgreen, gdArc );
      gdImageStringFT( im,NULL,white, FNT,FSZ,0.0, XCENT1-FSX, FSY, LABEL1 );
      centerx = XCENT1   ;
      oxh = centerx + 0.5*derth;
      oxl = centerx - 0.5*derth;

      satangle = rad*0.0 ;
      c  = cos(satangle) ;
      s  = sin(satangle) ;
      tx = cx-th*s       ;
      ty = cy-th*c       ;

      for( satdraw = -dcell ; satdraw <= dcell ; satdraw += 1.0 ) {

         double  wx =  satdraw*c ;
         double  wy = -satdraw*s ;

         ox = centerx + (int) ( tx + wx ) ;
         oy = centery + (int) ( ty + wy ) ;

         gdImageFilledArc(im, ox, oy, sth, sth, 0, 360, red  , gdArc);

         ox = centerx + (int) ( cx + wx ) ;
         oy = centery + (int) ( cy + wy ) ;

         if( ( ox > oxh ) || ( ox < oxl ) || ( oy > centery ) ) {
            gdImageFilledArc(im, ox, oy, sth, sth, 0, 360, white , gdArc);
         } else {
            gdImageFilledArc(im, ox, oy, sth, sth, 0, 360, gray  , gdArc);
         }
      }

      // min nightlight -----------------------------------------------

      gdImageFilledArc(im, XCENT2,YCENT, derth,derth, 0, 180,  green, gdArc );
      gdImageFilledArc(im, XCENT2,YCENT, derth,derth, 180, 0, dgreen, gdArc );
      gdImageStringFT( im,NULL,white, FNT,FSZ,0.0, XCENT2-FSX, FSY, LABEL2 );
      centerx = XCENT2   ;
      oxh = centerx + 0.5*derth;
      oxl = centerx - 0.5*derth;

      if( ( angle < rad*90.0 ) || ( angle > rad*270.0 ) ) {
         satangle = rad*0.0 ;
      } else if( ( angle < rad*210.0 ) && ( angle > rad*150.0 ) ) {
         satangle = 4.0*angle + rad*180.0 ;
      } else if( angle > rad*180 ) {
         satangle = angle + rad*90.0 ;
      } else {
         satangle = angle - rad*90.0 ;
      }
      c  = cos(satangle) ;
      s  = sin(satangle) ;
      tx = cx-th*s       ;
      ty = cy-th*c       ;

      for( satdraw = -dcell ; satdraw <= dcell ; satdraw += 1.0 ) {

         double  wx =  satdraw*c ;
         double  wy = -satdraw*s ;

         ox = centerx + (int) ( tx + wx ) ;
         oy = centery + (int) ( ty + wy ) ; 

         gdImageFilledArc(im, ox, oy, sth, sth, 0, 360, red  , gdArc);

         ox = centerx + (int) ( cx + wx ) ;
         oy = centery + (int) ( cy + wy ) ;

         if( ( ox > oxh ) || ( ox < oxl ) || ( oy > centery ) ) {
            gdImageFilledArc(im, ox, oy, sth, sth, 0, 360, white , gdArc);
         } else {
            gdImageFilledArc(im, ox, oy, sth, sth, 0, 360, gray  , gdArc);
         }
      }

      // zero nightlight ----------------------------------------------
      
      gdImageFilledArc(im, XCENT3,YCENT, derth,derth, 0, 180,  green, gdArc );
      gdImageFilledArc(im, XCENT3,YCENT, derth,derth, 180, 0, dgreen, gdArc );
      gdImageStringFT( im,NULL,white, FNT,FSZ,0.0, XCENT3-FSX, FSY, LABEL3 );
      centerx = XCENT3 ;
      oxh = centerx + 0.5*derth;
      oxl = centerx - 0.5*derth;

      if( ( angle < rad*90.0 ) || ( angle > rad*270.0 ) ) {
         satangle = rad*0.0 ;
      } else if( ( angle < rad*210.0 ) && ( angle > rad*150.0 ) ) {
         satangle = 3.0*angle + rad*0.0 ;
      } else {
         double  xx =  sin( angle ) ;
         double  yy = -cos( angle ) ;

         if ( xx > 0.0 ) {
            satangle = atan2 (  yy,  xx-0.5 );
         } else {
            satangle = atan2 ( -yy, -xx-0.5 );
         }
      }

      c  = cos(satangle) ;
      s  = sin(satangle) ;
      tx = cx-th*s       ;
      ty = cy-th*c       ;

      for( satdraw = -dcell ; satdraw <= dcell ; satdraw += 1.0 ) {

         double  wx =  satdraw*c ;
         double  wy = -satdraw*s ;

         ox = centerx + (int) ( tx + wx ) ;
         oy = centery + (int) ( ty + wy ) ;
         
         gdImageFilledArc(im, ox, oy, sth, sth, 0, 360, red  , gdArc);

         ox = centerx + (int) ( cx + wx ) ;
         oy = centery + (int) ( cy + wy ) ;
         
         if( ( ox > oxh ) || ( ox < oxl ) || ( oy > centery ) ) { 
            gdImageFilledArc(im, ox, oy, sth, sth, 0, 360, white , gdArc);
         } else {
            gdImageFilledArc(im, ox, oy, sth, sth, 0, 360, gray  , gdArc);
         }
      }

      // ---------------------------------------------------------------

      sprintf( framename, "%sdir/a%04d.png", NAME, frame );
      pngout = fopen( framename, "wb");
      gdImagePngEx( im, pngout, 1 );
      gdImageDestroy(im);
      fclose(pngout);
      printf( "%04d/%04d frames rendered\r", frame, NFRAME );
      fflush( stdout );
   }
   printf("%04d/%04d frames rendered, now make flash animation\n",frame,NFRAME);

   sprintf( cmdstr, "png2swf -o %s.swf -r 20 -j 100 %sdir/*.png", NAME, NAME ); 
   system(  cmdstr );
   printf( "All done, flash animation complete\n" );
}
