[net.micro.amiga] mand1.c

rj@amiga.UUCP (Robert J. Mical) (12/31/85)

/*
                   MAND1.C - Graphics routines
             Mandelbrot Self-Squared Dragon Generator
                    For the Commodore Amiga
                         Version 1.00

                      Accompanies MAND.C

             Copyright (C) 1985, Robert S. French
                  Placed in the Public Domain

     Assorted Goodies and Intuition-stuff by =RJ Mical=  1985
      Hope you appreciate them.  I especially like the zoom.

This program may be distributed free of charge as long as the above
notice is retained.

*/


#include "mand.h"


extern int MathBase, MathTransBase;


/*----------------------*/
/* Graphics definitions */

extern struct   GfxBase       *GfxBase;
extern struct   IntuitionBase *IntuitionBase;
 
extern struct   RastPort      *rp,*rp2;
extern struct   ViewPort      *vp;
 
extern struct   Window        *w,*w2;
extern struct   Screen        *screen;
extern struct   IntuiMessage  *message;
 
extern long last_color;

extern BOOL SettingCenter, SettingBoxSize;

/*----------------------------------*/
/* Miscellaneous Global Definitions */

extern union kludge {
   float f;
   int i;
} start_r,end_r,start_i,end_i;  /* Block bounds for set */
extern int max_x,max_y;  /* Graphics window size */
extern int max_count,color_inc,color_offset,color_set,color_mode,color_div;
extern int color_inset,func_num;

extern int v_starty,max_mem;
extern long v_offset;
extern UWORD *color_table,*v_mand_store;

extern int modified,want_read;

extern FILE *console,*v_fp,*redir_fp;
 
extern SHORT ZoomCenterX, ZoomCenterY, ZoomBoxSizeX, ZoomBoxSizeY;
extern SHORT ZoomBoxStartX, ZoomBoxStartY;


/*----------------*/
/* Color routines */

init_colors()
{
   switch (color_set) {
      case 0: init_cincr(); break;
      case 1: init_c7rot(); break;
   }
}

init_cincr()
/* this routine initializes the color table with sequential values from
 * 0 to 4095
 */
{
   UWORD i;

   for (i=0;i<4096;i++)
      *(color_table + i) = i;
}


init_c7rot()
/* this routine initializes the color table with this pattern:
 * 0 = 0
 * 1-15 = unit steps of blue
 * 16-30 = unit steps of green
 * 31-45 = unit steps of red
 * 46-60 = unit steps of sky sky blue (blue and green)
 * 61-75 = unit steps of purple (blue and red)
 * 76-90 = unit steps of yellow (green and red)
 * 91-115 = unit steps of white (all colors)
 */
{
   UWORD i,j,*base;

   base = color_table;
   *(base++) = 0;

   for (j = 0; j < 39; j++) {
      for (i = 1; i < 16; i++)
         *(base++) = i; /* gimme the blues */
      for (i = 1; i < 16; i++)
         *(base++) = i << 4; /* these are the greens */
      for (i = 1; i < 16; i++)
         *(base++) = i << 8; /* the reds */
      for (i = 1; i < 16; i++)
         *(base++) = i | (i << 4); /* blue and green */
      for (i = 1; i < 16; i++)
         *(base++) = i | (i << 8); /* blue and red */
      for (i = 1; i < 16; i++)
         *(base++) = (i << 4) | (i << 8); /* green and red */
      for (i = 1; i < 16; i++)
         *(base++) = i | (i << 4) | (i << 8); /* all three */
   }
}


gen_mand()
{
   void write_out();

   int x_coord,y_coord,count;
   union kludge x_gap,y_gap,z_r,z_i,u_r,u_i,temp,temp2,temp3,const0;
   union kludge const1,const2,const12;
   ULONG class;
   USHORT code;

    /* if there was a display open, close it now */
   CloseDisplay();
   /* reset the display variables: */
   SettingCenter = SettingBoxSize = FALSE;

   if (v_fp) {
      fclose(v_fp);
      v_fp = NULL;
   }

   v_fp = fopen("Mandelbrot.temp.file","w+");
   if (v_fp == NULL) {
      abort("Can't open temporary file!");
   }

   v_starty = 1;
   v_offset = 0L;
   modified = FALSE;
   want_read = FALSE;
   ZoomCenterX = (max_x >> 1);
   ZoomCenterY = (max_y >> 1);
   ZoomBoxSizeX = max_x;
   ZoomBoxSizeY = max_y;

   if (open_winds())
      return (1);

   x_gap.i = SPDiv(SPFlt(max_x),SPSub(start_r.i,end_r.i));
   y_gap.i = SPDiv(SPFlt(max_y),SPSub(start_i.i,end_i.i));

   const0.i = SPFlt(0);
   const1.i = SPFlt(1);
   const2.i = SPFlt(2);
   const12.i = SPDiv(SPFlt(2),SPFlt(1));

   for (y_coord = 0; y_coord < max_y; y_coord++)
      {
      last_color = 0xfff;
      v_pos_line(y_coord);
      modified = TRUE;
      for (x_coord = 0; x_coord < max_x; x_coord++)
         {
         while (message = (struct IntuiMessage *)GetMsg(w->UserPort))
            {
            class = message->Class;
            code  = message->Code;
            ReplyMsg(message);
            if (class == MENUPICK)
               {
               switch MENUNUM(code)
                  {
                  case MENU_OPTIONS:
                     switch ITEMNUM(code)
                        {
                        case OPTIONS_STOP:
                           return (0);
                        case OPTIONS_CLOSE:
                           CloseDisplay();
                           fclose(v_fp);
                           v_fp = NULL;
                           return (1);
                        }
                  }
               }
            }

         if (func_num == 0)
            z_r.i = const0.i;
         else
            z_r.i = const12.i;

         z_i.i = const0.i;
         u_r.i = SPAdd(start_r.i,SPMul(SPFlt(x_coord),x_gap.i));
         u_i.i = SPAdd(start_i.i,SPMul(SPFlt(max_y-y_coord-1),y_gap.i));
         count = 0;
         for (count = 0;
              SPFix( SPAdd( SPMul(z_r.i, z_r.i), SPMul(z_i.i,z_i.i))) < 4
                 && (count < max_count);
              count++) {
            if (func_num == 0) {  /* z = z^2-u */
               temp.i = SPSub(u_r.i,SPSub(SPMul(z_i.i,z_i.i),SPMul(z_r.i,z_r.i)));
               z_i.i = SPSub(u_i.i,SPMul(SPMul(const2.i,z_r.i),z_i.i));
               z_r = temp;
            }
            else if (func_num == 1) {  /* z = uz(1-z) */
               temp2.i = SPSub(z_r.i,const1.i);
               temp3.i = SPNeg(z_i.i);
               temp.i = SPSub(SPMul(temp3.i,z_i.i),SPMul(temp2.i,z_r.i));
               z_i.i = SPAdd(SPMul(temp2.i,z_i.i),SPMul(temp3.i,z_r.i));
               z_r = temp;
               temp.i = SPSub(SPMul(z_i.i,u_i.i),SPMul(z_r.i,u_r.i));
               z_i.i = SPAdd(SPMul(z_r.i,u_i.i),SPMul(z_i.i,u_r.i));
               z_r = temp;
            }
         }
         if (count >= max_count)
            count = 0;
         *(v_mand_store+(y_coord-v_starty)*max_x+x_coord) = count;
         write_out(count,x_coord,y_coord);
         }

   }
   DisplayBeep(NULL); /* hey, we're done! */
   return (0);
}
 
disp_mand()
{
   void write_out();

   int x_coord,y_coord,count;

   if (open_winds())
      return (1);

   want_read = TRUE;

   for (y_coord=0;y_coord<max_y;y_coord++) {
      last_color = 0xfff;
      v_pos_line(y_coord);
      for (x_coord=0;x_coord<max_x;x_coord++) {
         count = *(v_mand_store+(y_coord-v_starty)*max_x+x_coord);
         write_out(count,x_coord,y_coord);
      }
   }

   return (0);
}

void write_out(count,x,y)
int count,x,y;
{
   void ham_write();
   SHORT modulus;
   int color;

   y += STARTY;

   if (!(color_mode & NOT_HOLDANDMODIFY)) {
      if (count == 0)
         color = color_inset;
      else
         color = count * color_inc + color_offset;
      ham_write(*(color_table+color),x,y);
   }
   else /* we're not hold-and-modify, so ... */ {
      if (color_mode & HIRES_MODE) modulus = 13;
      else modulus = 29;

      if (count == 0) color = 2;
      else color = (((count - 1) / color_div) % modulus) + 3;
      SetAPen(rp, color);
      WritePixel(rp, x, y);
   }
}

void ham_write(color, x, y)
int color;
int x, y;
{
   if ((color & 0xf00) != (last_color & 0xf00)) {
      SetAPen(rp,((color & 0xf00) >> 8) + 0x20);
      WritePixel(rp,x,y);
      last_color = (last_color & 0xff) | (color & 0xf00);
      return;
   }

   if ((color & 0xf0) != (last_color & 0xf0)) {
      SetAPen(rp,((color & 0xf0) >> 4) + 0x30);
      WritePixel(rp,x,y);
      last_color = (last_color & 0xf0f) | (color & 0xf0);
      return;
   }

   SetAPen(rp,(color & 0xf) + 0x10);
   WritePixel(rp,x,y);
   last_color = (last_color & 0xff0) | (color & 0xf);
   return;
}


DrawZoomCenter()
{
   SetDrMd(w->RPort, COMPLEMENT);
   Move(w->RPort, 0, ZoomCenterY);
   Draw(w->RPort, max_x, ZoomCenterY);
   Move(w->RPort, ZoomCenterX, 0);
   Draw(w->RPort, ZoomCenterX, max_y);
}


RecalcZoomBox()
{
   ZoomBoxSizeX = (abs(w->MouseX - ZoomCenterX) << 1) + 1;
   ZoomBoxSizeY = (abs(w->MouseY - ZoomCenterY) << 1) + 1;
   if (w->MouseX < ZoomCenterX) ZoomBoxStartX = w->MouseX;
   else ZoomBoxStartX = ZoomCenterX - ((ZoomBoxSizeX - 1) >> 1);
   if (w->MouseY < ZoomCenterY) ZoomBoxStartY = w->MouseY;
   else ZoomBoxStartY = ZoomCenterY - ((ZoomBoxSizeY - 1) >> 1);
}


DrawZoomBox()
{
   SHORT endx, endy;

   endx = ZoomBoxStartX + ZoomBoxSizeX - 1;
   endy = ZoomBoxStartY + ZoomBoxSizeY - 1;

   SetDrMd(w->RPort, COMPLEMENT);
   Move(w->RPort, ZoomBoxStartX, ZoomBoxStartY);
   Draw(w->RPort, ZoomBoxStartX, endy);
   Draw(w->RPort, endx, endy);
   Draw(w->RPort, endx, ZoomBoxStartY);
   Draw(w->RPort, ZoomBoxStartX, ZoomBoxStartY);
}


CloseDisplay()
{
   if (w) CloseWindow(w);
   if (screen) CloseScreen(screen);
   w = screen = NULL;
}

rj@amiga.UUCP (Robert J. Mical) (01/11/86)

/*
                   MAND1.C - Graphics routines
             Mandelbrot Self-Squared Dragon Generator
                    For the Commodore Amiga
                         Version 2.01

             Copyright (C) 1985, Robert S. French
            Vastly Enhanced by =RJ Mical=  1985/86
            Copyright (C) 1986,  =Robert J. Mical=
                 Placed in the Public Domain


This program may be distributed free of charge as long as the above
notice is retained.

*/


#include "mand.h"


extern int MathBase, MathTransBase;

extern struct Menu MainMenu[MENU_COUNT];
extern struct MenuItem OptionsItems[OPTIONS_COUNT];


extern SHORT Color0, Color1, Color2;
extern SHORT UserPalette[29];

/*----------------------*/
/* Graphics definitions */

extern struct   GfxBase       *GfxBase;
extern struct   IntuitionBase *IntuitionBase;
 
extern struct   RastPort      *rp,*rp2;
extern struct   ViewPort      *vp;
 
extern struct   Window        *w,*w2, *ColorWindow;
extern struct   Screen        *screen;
extern struct   IntuiMessage  *message;
 
extern long last_color;

extern BOOL SettingCenter, SettingBoxSize, SetBoxProportional;

/*----------------------------------*/
/* Miscellaneous Global Definitions */

extern union kludge {
   float f;
   int i;
} start_r,end_r,start_i,end_i;  /* Block bounds for set */
extern int max_x,max_y;  /* Graphics window size */
extern int max_count,color_inc,color_offset,color_set,color_mode,color_div;
extern int color_inset,func_num;

extern int v_starty,max_mem;
extern long v_offset;
extern UWORD *color_table,*v_mand_store;

extern int modified,want_read;

extern FILE *console,*v_fp,*redir_fp;
 
extern SHORT ZoomCenterX, ZoomCenterY, ZoomBoxSizeX, ZoomBoxSizeY;
extern SHORT ZoomBoxStartX, ZoomBoxStartY;


/*----------------*/
/* Color routines */

init_colors()
{
   switch (color_set) {
      case 0: init_cincr(); break;
      case 1: init_c7rot(); break;
      case 2: copy_userpalette(); break;
   }
}

init_cincr()
/* this routine initializes the color table with sequential values from
 * 0 to 4095
 */
{
   UWORD i;

   for (i=0;i<4096;i++)
      *(color_table + i) = i;
}


init_c7rot()
/* this routine initializes the color table with this pattern:
 * 0 = 0
 * 1-15 = unit steps of blue
 * 16-30 = unit steps of green
 * 31-45 = unit steps of red
 * 46-60 = unit steps of sky sky blue (blue and green)
 * 61-75 = unit steps of purple (blue and red)
 * 76-90 = unit steps of yellow (green and red)
 * 91-115 = unit steps of white (all colors)
 */
{
   UWORD i,j,*base;

   base = color_table;
   *(base++) = 0;

   for (j = 0; j < 39; j++) {
      for (i = 1; i < 16; i++)
         *(base++) = i; /* gimme the blues */
      for (i = 1; i < 16; i++)
         *(base++) = i << 4; /* these are the greens */
      for (i = 1; i < 16; i++)
         *(base++) = i << 8; /* the reds */
      for (i = 1; i < 16; i++)
         *(base++) = i | (i << 4); /* blue and green */
      for (i = 1; i < 16; i++)
         *(base++) = i | (i << 8); /* blue and red */
      for (i = 1; i < 16; i++)
         *(base++) = (i << 4) | (i << 8); /* green and red */
      for (i = 1; i < 16; i++)
         *(base++) = i | (i << 4) | (i << 8); /* all three */
   }
}


copy_userpalette()
{
    SHORT i;

    for (i = 0; i <= 28; i++)
	*(color_table + color_offset + (i + 1) * color_inc) = UserPalette[i];
}


gen_mand()
{
   void write_out();

   int x_coord,y_coord,count;
   union kludge x_gap,y_gap,z_r,z_i,u_r,u_i,temp,temp2,temp3,const0;
   union kludge const1,const2,const12;
   ULONG class;
   USHORT code;
   int returncode;
   int z_r_squared, z_i_squared;

    /* if there was a display open, close it now */
   CloseDisplay();

   /* show the current settings! */
   CurrentSettings();

   /* reset the display variables: */
   SettingCenter = SettingBoxSize = FALSE;

   if (v_fp) {
      fclose(v_fp);
      v_fp = NULL;
   }

   v_fp = fopen("Mandelbrot.temp.file","w+");
   if (v_fp == NULL) {
      abort("Can't open temporary file!");
   }

   v_starty = 1;
   v_offset = 0L;
   modified = FALSE;
   want_read = FALSE;
   ZoomCenterX = (max_x >> 1);
   ZoomCenterY = (max_y >> 1);
   ZoomBoxSizeX = max_x;
   ZoomBoxSizeY = max_y;

   if (open_winds())
      {
      returncode = 1;
      goto OPEN_W_RETURN;
      }

   x_gap.i = SPDiv(SPFlt(max_x),SPSub(start_r.i,end_r.i));
   y_gap.i = SPDiv(SPFlt(max_y),SPSub(start_i.i,end_i.i));

   const0.i = SPFlt(0);
   const1.i = SPFlt(1);
   const2.i = SPFlt(2);
   const12.i = SPDiv(SPFlt(2),SPFlt(1));

   for (y_coord = 0; y_coord < max_y; y_coord++)
      {
      last_color = 0xfff;
      v_pos_line(y_coord);
      modified = TRUE;
      for (x_coord = 0; x_coord < max_x; x_coord++)
         {
         while (message = (struct IntuiMessage *)GetMsg(w->UserPort))
            {
            class = message->Class;
            code  = message->Code;
            ReplyMsg(message);
            if (class == MENUPICK)
               {
               /* the menu strip is hacked up to a minimal set during gen_m */
               switch MENUNUM(code)
                  {
                  case 0:
                     switch ITEMNUM(code)
                        {
                        case 0:
                           returncode = 0;
			   goto OPEN_W_RETURN;
                        case 1:
                           CloseDisplay();
                           fclose(v_fp);
                           v_fp = NULL;
                           returncode = 1;
			   goto OPEN_W_RETURN;
                        }
                     break;
                  }
               }
            }

         if (func_num == 0)
            z_r.i = const0.i;
         else
            z_r.i = const12.i;

         z_i.i = const0.i;
         u_r.i = SPAdd(start_r.i,SPMul(SPFlt(x_coord),x_gap.i));
         u_i.i = SPAdd(start_i.i,SPMul(SPFlt(max_y-y_coord-1),y_gap.i));
         for (count = 0; count < max_count; count++)
            {
	    /* By setting these variables and reusing the results below,
	     * we save approximately 10% execution time in this 
	     * innermost of inner loops.
	     */
            z_r_squared = SPMul(z_r.i, z_r.i);
	    z_i_squared = SPMul(z_i.i, z_i.i);
            if ( SPFix(SPAdd(z_r_squared, z_i_squared)) >= 4 ) break;
            if (func_num == 0)
               {  /* z = z^2-u */
               temp.i = SPSub(u_r.i, SPSub(z_i_squared, z_r_squared));
               z_i.i = SPSub(u_i.i, SPMul(SPMul(const2.i,z_r.i), z_i.i));
               z_r = temp;
               }
            else if (func_num == 1)
               {  /* z = uz(1-z) */
               temp2.i = SPSub(z_r.i,const1.i);
               temp3.i = SPNeg(z_i.i);
               temp.i = SPSub(SPMul(temp3.i,z_i.i),SPMul(temp2.i,z_r.i));
               z_i.i = SPAdd(SPMul(temp2.i,z_i.i),SPMul(temp3.i,z_r.i));
               z_r = temp;
               temp.i = SPSub(SPMul(z_i.i,u_i.i),SPMul(z_r.i,u_r.i));
               z_i.i = SPAdd(SPMul(z_r.i,u_i.i),SPMul(z_i.i,u_r.i));
               z_r = temp;
               }
            }

         if (count >= max_count)
            count = 0;
         *(v_mand_store+(y_coord-v_starty)*max_x+x_coord) = count;
         write_out(count,x_coord,y_coord);
         }

   }

   /* successful return with window opened */
   returncode = 0;
   DisplayBeep(NULL); /* hey, we're done! */
   /* Now that we're drawing the primary display, 
    * restore the entire menu system 
    */

OPEN_W_RETURN:
   if (returncode == 0)
      {
      MainMenu[MENU_OPTIONS].NextMenu = &MainMenu[MENU_ZOOM];
      MainMenu[MENU_OPTIONS].FirstItem = &OptionsItems[0];
      SetMenuStrip(w, &MainMenu[0]);
      }

   return(returncode);
}
 
disp_mand()
{
   void write_out();

   int x_coord,y_coord,count;

   if (open_winds())
      return (1);

   want_read = TRUE;

   for (y_coord=0;y_coord<max_y;y_coord++) {
      last_color = 0xfff;
      v_pos_line(y_coord);
      for (x_coord=0;x_coord<max_x;x_coord++) {
         count = *(v_mand_store+(y_coord-v_starty)*max_x+x_coord);
         write_out(count,x_coord,y_coord);
      }
   }

   return (0);
}

void write_out(count,x,y)
int count,x,y;
{
   void ham_write();
   SHORT modulus;
   int color;

   y += STARTY;

   if (!(color_mode & NOT_HOLDANDMODIFY)) {
      if (count == 0)
         color = color_inset;
      else
         color = count * color_inc + color_offset;
      ham_write(*(color_table+color),x,y);
   }
   else /* we're not hold-and-modify, so ... */ {
      if (color_mode & HIRES_MODE) modulus = 13;
      else modulus = 29;

      if (count == 0) color = 2;
      else color = (((count - 1) / color_div) % modulus) + 3;
      SetAPen(rp, color);
      WritePixel(rp, x, y);
   }
}

void ham_write(color, x, y)
int color;
int x, y;
{
   if ((color & 0xf00) != (last_color & 0xf00)) {
      SetAPen(rp,((color & 0xf00) >> 8) + 0x20);
      WritePixel(rp,x,y);
      last_color = (last_color & 0xff) | (color & 0xf00);
      return;
   }

   if ((color & 0xf0) != (last_color & 0xf0)) {
      SetAPen(rp,((color & 0xf0) >> 4) + 0x30);
      WritePixel(rp,x,y);
      last_color = (last_color & 0xf0f) | (color & 0xf0);
      return;
   }

   SetAPen(rp,(color & 0xf) + 0x10);
   WritePixel(rp,x,y);
   last_color = (last_color & 0xff0) | (color & 0xf);
   return;
}


DrawZoomCenter()
{
    DrawCross(ZoomCenterX, ZoomCenterY);
}

DrawDisplayCenter()
{
    DrawCross(max_x >> 1, max_y >> 1);
}


DrawCross(x, y)
SHORT x, y;
{
   SetDrMd(w->RPort, COMPLEMENT);
   Move(w->RPort, 0, y);
   Draw(w->RPort, max_x, y);
   Move(w->RPort, x, 0);
   Draw(w->RPort, x, max_y);
}


RecalcZoomBox()
{
    ZoomBoxSizeY = (abs(w->MouseY - ZoomCenterY) << 1) + 1;
    if (w->MouseY < ZoomCenterY) ZoomBoxStartY = w->MouseY;
    else ZoomBoxStartY = ZoomCenterY - ((ZoomBoxSizeY - 1) >> 1);

    /* if SetBoxProportional, size X proportional to Y */
    if (SetBoxProportional)
	{
	ZoomBoxSizeX = (ZoomBoxSizeY * 8) / 5;
	ZoomBoxStartX = ZoomCenterX - ((ZoomBoxSizeX - 1) >> 1);
	}
    else
	{
	ZoomBoxSizeX = (abs(w->MouseX - ZoomCenterX) << 1) + 1;
	if (w->MouseX < ZoomCenterX) ZoomBoxStartX = w->MouseX;
	else ZoomBoxStartX = ZoomCenterX - ((ZoomBoxSizeX - 1) >> 1);
	}
}


DrawZoomBox()
{
   SetDrMd(w->RPort, COMPLEMENT);
   DrawBox(w->RPort, ZoomBoxStartX, ZoomBoxStartY, 
         ZoomBoxStartX + ZoomBoxSizeX - 1,
         ZoomBoxStartY + ZoomBoxSizeY - 1);

}


CloseDisplay()
{
   if (w) CloseWindow(w);
   if (w2) CloseWindow(w2);
   if (ColorWindow) CloseWindow(ColorWindow);
   if (screen) CloseScreen(screen);
   w = NULL;
   screen = NULL;
}



DrawBox(rp, x1, y1, x2, y2)
struct RastPort *rp;
SHORT x1, y1, x2, y2;
/* draws a box without overlapping the edges (in case of complement mode) */
{
    Move(rp, x1, y1 + SIGN(y2 - y1));
    Draw(rp, x1, y2);  
    Move(rp, x1 + SIGN(x2 - x1), y2);
    Draw(rp, x2, y2);  
    Move(rp, x2, y2 - SIGN(y2 - y1));
    Draw(rp, x2, y1); 
    Move(rp, x2 - SIGN(x2 - x1), y1);
    Draw(rp, x1, y1);
}