// gcc -o g200 g200.c -lgd -lpng -lm ; ./g200
//
// 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        "g200"
#define  LABEL0      "Max NLP"
#define  LABEL3      "Zero NLP"
#define  NFRAME      120
#define  XFRAME      1024
#define  YFRAME      768
#define  R00         200
#define  XCENT0      (512-240)
#define  XCENT3      (512+240)
#define  YCENT       250
#define  SATSIZE     50
#define  DG          16
#define  FSZ         30
#define  FSX         100
#define  FSY         40
#define  FNT         "DejaVuMonoSans"
#define  P1          490
#define  P0          670
#define  PX0         (XCENT0)
#define  PX1         (XCENT3)

#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
   // graph parameters and data arrays
   int     pmax[NFRAME]             ;
   int     pzero[NFRAME]            ;
   int     px[NFRAME]               ;
   double  pxscale = ((double)(PX1-PX0))/((double)NFRAME);
   double  pyscale = (double)(P1-P0);
   int     pf                       ;

   gdImagePtr         im            ; // Declare the image

   //------------------------------------------------------------
   // make directory

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

   // make graph points
   for( pf=0 ; pf < NFRAME ;  pf++ ) {
      
      double angle = dangle*((double)pf);
      double cx = r00*sin(angle);
      double cy = -r00*cos(angle);
      double dh = 0.5*( (double) derth );
      
      px[pf] = PX0 + (int)( pxscale * ((double)pf )) ;

      if(     cy > 0.0 ) {      // Front side
         pmax[ pf] = P1 ;
         pzero[pf] = P1 ;
      }
      else if( cx > dh ) {     // Back right
         pmax[ pf] = P1 ;
         double dx = cx-dh ;
         double cc = dx / sqrt(dx*dx+cy*cy) ;
         pzero[pf] = P0 + (int)( pyscale*cc ) ;
      }
      else if( cx < -dh ) {     // Back right
         pmax[ pf] = P1 ;
         double dx = -(cx+dh) ;
         double cc = dx / sqrt(dx*dx+cy*cy) ;
         pzero[pf] = P0 + (int)( pyscale*cc ) ;
      }
      else                {     // Night
         pmax[ pf] = P0 ;
         pzero[pf] = P0 ;
      } 
   }

   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, 3 ) ;

      // draw graph
      gdImageLine( im, PX0, P0, PX1, P0, gray );
      gdImageLine( im, PX0, P1, PX1, P1, gray );
      gdImageLine( im, PX0, P0, PX0, P1, gray );
      gdImageLine( im, PX1, P0, PX1, P1, gray );

      for( pf = 1 ; pf < NFRAME ; pf++ ) {
         int pm = pf-1 ;
         gdImageLine( im, px[pm], pmax[pm] , px[pf], pmax[pf],    red );
         gdImageLine( im, px[pm], pzero[pm], px[pf], pzero[pf], green );
      }
      gdImageFilledArc(im,px[frame],pmax[ frame],DG,DG, 180,0,   red, gdArc );
      gdImageFilledArc(im,px[frame],pzero[frame],DG,DG, 0,180, green, gdArc );

      gdImageStringFT( im,NULL,white, FNT,FSZ,0.0, PX0+80, P0-15, "Thinsat Power" );

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

      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             ;

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

      gdImageFilledArc(im, XCENT0,YCENT, derth,derth, 0, 180, dgreen, gdArc );
      gdImageFilledArc(im, XCENT0,YCENT, derth,derth, 180, 0,  green, gdArc );
      gdImageStringFT( im,NULL,red, FNT,FSZ,0.0, XCENT0-FSX, FSY, LABEL0 );
      centerx = XCENT0   ;
      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);
         }
      }

      // zero nightlight ----------------------------------------------
      
      gdImageFilledArc(im, XCENT3,YCENT, derth,derth, 0, 180, dgreen, gdArc );
      gdImageFilledArc(im, XCENT3,YCENT, derth,derth, 180, 0,  green, gdArc );
      gdImageStringFT( im,NULL,green, 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*30.0 ) || ( angle > rad*330.0 ) ) {
         satangle =  3.0*angle + rad*180.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       ;    // - to +
      ty = cy+th*c       ;    // - to +

      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 50 %sdir/*.png", NAME, NAME ); 
   system(  cmdstr );

   sprintf( cmdstr, "png2swf -X 512 -o %s_512.swf -r 20 -j 50 %sdir/*.png", NAME, NAME ); 
   system(  cmdstr );

   sprintf( cmdstr, "png2swf -X 384 -o %s_384.swf -r 20 -j 50 %sdir/*.png", NAME, NAME ); 
   system(  cmdstr );

   sprintf( cmdstr, "png2swf -X 256 -o %s_256.swf -r 20 -j 50 %sdir/*.png", NAME, NAME ); 
   system(  cmdstr );

   printf( "All done, flash animation complete\n" );
}
