#include "INCLUDE:Lattice/math.h"
#include "INCLUDE:Lattice/stdio.h"
#include "INCLUDE:libraries/dos.h"
#include "INCLUDE:exec/types.h"
#include "INCLUDE:graphics/gfx.h"
#include "INCLUDE:graphics/gfxmacros.h"
#include "INCLUDE:exec/exec.h"
#include "INCLUDE:exec/execbase.h"
#include "INCLUDE:graphics/view.h"
#include "INCLUDE:graphics/gfxbase.h"
#include "INCLUDE:graphics/text.h"
#include "INCLUDE:exec/libraries.h"
#include "INCLUDE:intuition/intuition.h"

#include "qman_data.include"

/*---------------------------------------*/
/*                                       */
/*           //   QMan !   //            */
/*                                       */
/*    (That's supposed to stand for      */
/*        "Quick Mandelbrot.")           */
/*---------------------------------------*/

void main()
{

GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);


scale = 67108864.0;     /*    2 ** 26   */
xptr = (int)&x_table[0];

kflag = 1;   /*   start off looking at the skew set  */

Restart:

restart_selected = FALSE;

top     =  1.1;
bottom  = -1.1;

if ( kflag == 1 ) {
  left  = -1.5;
  right =  1.0;   }
else              {
  left  = -2.0;
  right =  0.5;   }

random_colors = FALSE;

cycle_colors =   1;   /*  initially cycle colors       */
ilace        =   2;   /*  start out without interlace  */
vertical_res = 200;
smooth_flag  =   1;   /*  smoothing is initially on    */


NewScreen:

  SetUpMandelGraphics();

  SetUpMandelMenus();

  SetMenuStrip( mandel_window, &qman  ); 


screen_changed = FALSE;

while (1 == 1) {

  NextPicture:

  Move( rp, 0, 0  );
  ClearScreen( rp );

  xincr   =  (right - left)/640.0;
  yincr   =  (top - bottom)/(double)vertical_res;

  left_x  = left;

  for (i = 0; i < 640; i++ )  {
    x_table[i] = scale * left_x;
    left_x = left_x + xincr;      }

  imagc = scale * top;
 
  /*  Set bit plane pointers for next Mandelbrot picture:  */
  bp1 = (int) rp -> BitMap -> Planes[0];
  bp2 = (int) rp -> BitMap -> Planes[1];
  bp3 = (int) rp -> BitMap -> Planes[2];
  bp4 = (int) rp -> BitMap -> Planes[3]; 

  new_region_selected = FALSE;

  for ( y = 0; y < vertical_res; y++ ) {

    message = (struct IntuiMessage *) GetMsg( mandel_window -> UserPort );


    if ( message != NULL ) {
      ProcessMessage();  

      if ( new_region_selected ) goto NextPicture;
      if ( screen_changed      ) goto NewScreen; 
      if ( restart_selected    ) goto Restart;    }


    if ( cycle_colors == 1 ) NextColor();

    /* Call the appropriate assembly routine to draw the current row: */
    if ( smooth_flag == 1 ) 
      msmooth();
    else
      mandel(); 

    imagc = imagc - scale * yincr;

    }  /* y-loop */


    /* - - - - - - - - - - - - - - - - - - - - - - - - - -*/
    cycle_count = 0;

    while( 1 == 1 ) { 
      cycle_count = (cycle_count + 1) % 4000;

      if ( (cycle_count == 0) && (cycle_colors == 1) ) NextColor();  
 
      message = (struct IntuiMessage *) GetMsg( mandel_window -> UserPort );

      if ( message != NULL ) {
        ProcessMessage();  

        if ( new_region_selected ) goto NextPicture;
        if ( screen_changed      ) goto NewScreen;  
        if ( restart_selected    ) goto Restart;   }

        } /* inner forever loop */
    /* - - - - - - - - - - - - - - - - - - - - - - - - - -*/

  }   /* outer forever loop  */


}  /* main */

/*--------------------------------------------*/

#include "qman_graphics.include"
#include "qman_menus.include"

/*--------------------------------------------*/

void ProcessMessage()
{
  struct MenuItem  *Item;

  if ( message -> Class != MENUPICK ) return;
  if ( message -> Code  == MENUNULL ) return;

  Item = (struct MenuItem *)ItemAddress( &qman, message -> Code );

  if ( Item -> Command == 'q' ) {
    CloseWindow( mandel_window );
    CloseScreen( mandel_screen );
    exit();
    } 

  if ( Item -> Command == 'n' )  NextColor();
  if ( Item -> Command == 'b' )  random_colors = FALSE;
  if ( Item -> Command == 'r' )  random_colors = TRUE;



  if ( Item -> Command == 'c' )            {  /* toggle cycle option:  */
 
    ClearMenuStrip( mandel_window );

    if ( cycle_colors == 1 )                  /* cycling currently on  */
      cycle.Flags = cycle.Flags ^ CHECKED;    /* turn cycling off      */
    else
      cycle.Flags = cycle.Flags | CHECKED;    /* turn cycling on       */

    cycle_colors =   3 - cycle_colors;

    SetMenuStrip( mandel_window, &qman );  } 


  if ( Item -> Command == 'm' )            {  /* toggle smoothing option: */
 
    ClearMenuStrip( mandel_window );

    if ( smooth_flag == 1 )                   /* smoothing currently on   */
      smooth.Flags = smooth.Flags ^ CHECKED;  /* turn smoothing off       */
    else
      smooth.Flags = smooth.Flags | CHECKED;  /* turn smoothing on        */

    smooth_flag = 3 - smooth_flag;

    SetMenuStrip( mandel_window, &qman );  } 


  if ( Item -> Command == 'k' )            {  /* toggle skew option:      */
 
    ClearMenuStrip( mandel_window );

    if ( kflag == 1 )                         /* skew currently on   */
      skew.Flags = skew.Flags ^ CHECKED;      /* turn skew off       */
    else
      skew.Flags = skew.Flags | CHECKED;      /* turn skew on        */

    kflag = 1 - kflag;

    SetMenuStrip( mandel_window, &qman );  }  


    if ( Item -> Command == 'i' )      { /* toggle ilace option:   */
      ilace   =   3 - ilace;
      vertical_res = 600 - vertical_res;
      screen_changed = TRUE;
      CloseWindow( mandel_window );
      CloseScreen( mandel_screen );    }

  if ( Item -> Command == 's' )        {
     restart_selected = TRUE;
     CloseWindow( mandel_window );
     CloseScreen( mandel_screen );     } 
         
  if ( Item -> Command == 'z' )  SelectZoom();

  ReplyMsg( message );

}  /*  end of ProcessMessage()    */

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - */

void NextColor()
{
   int permute, greenzap;

   if ( random_colors )            {
       for( i = 3; i < 13; i++)                {
         reds[i]   = lrand48() % 16;
         greens[i] = lrand48() % 16;
         blues[i]  = lrand48() % 16;
         SetRGB4( vp, i, reds[i], greens[i], blues[i] );   }
                                    }  /* random colors */

    else {  /* generate the colors a little less chaotically! */
         reds[3]   = lrand48() % 16;
         greens[3] = lrand48() % 16;
         blues[3]  = lrand48() % 16;
         greenzap  = lrand48() % 12;
         permute   = lrand48() %  6;

         for( i = 4; i < 13; i++)               { 
           reds[i]   = (reds[i-1]   +  1) % 16;
           greens[i] = (greens[i-1] + 15) % 16;
           if ( greenzap == 0 ) greens[i] = 0;
           blues[i]  = blues[3];

           switch( permute ) {

             case 0 :  SetRGB4(vp,i,reds[i],greens[i],blues[i]);  break; 
             case 1 :  SetRGB4(vp,i,reds[i],blues[i],greens[i]);  break; 
             case 2 :  SetRGB4(vp,i,greens[i],reds[i],blues[i]);  break;
             case 3 :  SetRGB4(vp,i,greens[i],blues[i],reds[i]);  break;
             case 4 :  SetRGB4(vp,i,blues[i],reds[i],greens[i]);  break;
             case 5 :  SetRGB4(vp,i,blues[i],greens[i],reds[i]);  break;
 
                             }  /* switch */
                                               }  /*  i-loop  */
 
         }    /*   else   */ 


}  /* End of NextColor  */

/* - - - - - - - - - - - - - - - - - - - - - - - - - */

void SelectZoom()

{
  struct IntuiMessage *click, *click2;
  int    IDCMP_flags, s3, t3;
  SHORT  quad[10];
  

  SetDrMd( rp, COMPLEMENT );
  SetAPen( rp, 1 );

  new_region_selected = TRUE;


  UpperLeft:

  WaitPort( mandel_window -> UserPort );
  click = (struct IntuiMessage *) GetMsg( mandel_window -> UserPort );

  if ( click -> Code != SELECTDOWN ) {
    ReplyMsg( click );
    goto UpperLeft;                  }

  left  = left + xincr * (double)click -> MouseX;
  top   = top  - yincr * (double)click -> MouseY;

  x1 = click -> MouseX;
  y1 = click -> MouseY;
  x3 = x1;
  y3 = y1; 


  IDCMP_flags = MOUSEBUTTONS | MENUPICK | MOUSEMOVE;
  ModifyIDCMP( mandel_window, IDCMP_flags ); 

  Move( rp, x1, y1 );
  quad[3] = y1;
  quad[6] = x1;
  quad[8] = x1;
  quad[9] = y1;

  LowerRight:

  WaitPort( mandel_window -> UserPort );
  click  = (struct IntuiMessage *) GetMsg( mandel_window -> UserPort );

  click2 = (struct IntuiMessage *) GetMsg( mandel_window -> UserPort );
  if (click2 != NULL ) {
    ReplyMsg( click );
    click = click2;    }

  if ( click -> Code != SELECTUP )  {
    s3 = click -> MouseX;
    t3 = click -> MouseY;

    ReplyMsg( click );

    if ( (s3 < x1) || (t3 < y1) ) goto LowerRight;

    x2 = x3;
    y2 = y3;
    x3 = s3;
    y3 = t3;

    quad[2] = x2;
    quad[4] = x2;
    quad[5] = y2;
    quad[7] = y2;

    PolyDraw( rp, 4, &quad[2] );

    quad[2] = x3;
    quad[4] = x3;
    quad[5] = y3;
    quad[7] = y3; 

    PolyDraw( rp, 4, &quad[2] );

    goto LowerRight;                }

  else ReplyMsg( click );


  right  = right   - xincr * (double)(640          - click -> MouseX);
  bottom = bottom  + yincr * (double)(vertical_res - click -> MouseY);

  IDCMP_flags = MOUSEBUTTONS | MENUPICK;
  ModifyIDCMP( mandel_window, IDCMP_flags );

  SetDrMd( rp, JAM1 ); 


}



