[net.micro.amiga] MAND1.C - Mandelbrot Set Repost

french@caip.RUTGERS.EDU (12/27/85)

From: "french robert%d.mfenet"@LLL-MFE.ARPA

/*
                   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

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

*/


/*-------------------*/
/* Lots of includes! */

#include <exec/types.h>
#include <exec/tasks.h>
#include <exec/libraries.h>
#include <exec/devices.h>
#include <devices/keymap.h>
#include <graphics/copper.h>
#include <graphics/display.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>
#include <graphics/view.h>
#include <graphics/gels.h>
#include <graphics/regions.h>
#include <hardware/blit.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <stdio.h>


/*-------------------*/
/* Misc. definitions */

#define EVER ;;
#define MAXX 640
#define MAXY 390
#define STARTY 10

#define TOPW2 w2->BorderTop
#define BOTTOMW2 (w2->Height - w2->BorderBottom)
#define LEFTW2 w2->BorderLeft
#define RIGHTW2 (w2->Width - w2->BorderRight)


/*---------------------------------*/
/* Fast-Floating-Point Definitions */

extern   int     SPFix();
extern   int     SPFlt();
extern   int     SPCmp();
extern   int     SPTst();
extern   int     SPAbs();
extern   int     SPNeg();
extern   int     SPAdd();
extern   int     SPSub();
extern   int     SPMul();
extern   int     SPDiv();
 
extern   int     SPAtan();
extern   int     SPSin();
extern   int     SPCos();
extern   int     SPTan();
extern   int     SPSincos();
extern   int     SPSinh();
extern   int     SPCosh();
extern   int     SPTanh();
extern   int     SPExp();
extern   int     SPLog();
extern   int     SPPow();
extern   int     SPSqrt();
extern   int     SPTieee();
extern   int     SPFieee();

extern int MathBase,MathTransBase;


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

extern struct   GfxBase       *GfxBase;
extern struct   IntuitionBase *IntuitionBase;
 
struct   RastPort      *rp,*rp2;
struct   ViewPort      *vp;
 
struct TextAttr TextFont =
    {
       "topaz.font", /* Standard system font */
       8,    0,    0
    };
 
struct   Window        *w,*w2;
struct   Screen        *screen;
struct   IntuiMessage  *message;
 
struct NewScreen ns = {
   0, 0,                               /* start position                */
   320, 200, 6,                        /* width, height, depth          */
   0, 1,                               /* detail pen, block pen         */
   HAM,                                /* Hold and Modify ViewMode      */
   CUSTOMSCREEN,                       /* screen type                   */
   &TextFont,                          /* font to use                   */
   "",                                 /* default title for screen      */
   NULL                                /* pointer to additional gadgets */
   };
 
struct NewWindow nw = {
         0, 0,                          /* start position                */
         320, 200,                      /* width, height                 */
         -1, -1,                        /* detail pen, block pen         */
         CLOSEWINDOW|MOUSEBUTTONS,      /* IDCMP flags                   */
         ACTIVATE|WINDOWCLOSE|BORDERLESS|BACKDROP,
                                        /* window flags                  */
         NULL,                          /* pointer to first user gadget  */
         NULL,                          /* pointer to user checkmark     */
         "Mandelbrot Dragons",          /* window title                  */
         NULL,                          /* pointer to screen (set below) */
         NULL,                          /* pointer to superbitmap        */
         0, 0, 320, 200,                /* ignored since not sizeable    */
         CUSTOMSCREEN                   /* type of screen desired        */
};

struct NewWindow aw = {
         0, 10,
         100, 70,
         -1, -1,
         NULL,
         WINDOWDRAG|WINDOWSIZING|SMART_REFRESH,
         NULL,
         NULL,
         "Analysis",
         NULL,
         NULL,
         0, 0, 320, 200,
         CUSTOMSCREEN
};

long last_color;


/*----------------------------------*/
/* 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;
 

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

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

init_cincr()
{
   UWORD i;

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

init_c7rot()
{
   UWORD i,j,*base;

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

   for (j=0;j<39;j++) {
      for (i=1;i<16;i++)
         *(base++) = i;
      for (i=1;i<16;i++)
         *(base++) = i << 4;
      for (i=1;i<16;i++)
         *(base++) = i << 8;
      for (i=1;i<16;i++)
         *(base++) = i | (i << 4);
      for (i=1;i<16;i++)
         *(base++) = i | (i << 8);
      for (i=1;i<16;i++)
         *(base++) = (i << 4) | (i << 8);
      for (i=1;i<16;i++)
         *(base++) = i | (i << 4) | (i << 8);
   }
}


/*----------------*/
/* Other routines */

open_winds()
{
   int i,color;

   nw.Width = max_x;
   nw.Height = max_y+STARTY;

   if (color_mode & 1) {
      ns.ViewModes = NULL;
      ns.Depth = 5;
   }
   else {
      ns.ViewModes = HAM;
      ns.Depth = 6;
   }

   if (color_mode & 2) {
      ns.ViewModes |= INTERLACE;
      ns.Height = 400;
   }
   else
      ns.Height = 200;

   if (color_mode & 4) {
      ns.Width = 640;
      ns.ViewModes |= HIRES;
      ns.Depth = 4;
   }
   else
      ns.Width = 320;

   screen = (struct Screen *)OpenScreen(&ns);
   if (screen == NULL) {
      fputs("Can't open new screen!\n",console);
      return (1);
   }
 
   ShowTitle(screen,FALSE);

   nw.Screen = screen;
   w = (struct Window *)OpenWindow(&nw);
   if (w == NULL) {
      CloseScreen(screen);
      fputs("Can't open new window!\n",console);
      return (1);
   }

   vp = &screen->ViewPort;
   rp = w->RPort;
 
   SetDrMd(rp,JAM1);
   SetBPen(rp, 0);

   if (color_mode & 1)
      for (i=0;i<28;i++) {
         color = *(color_table+i*color_inc);
         SetRGB4(vp,i+4,(color >> 8) & 0xf,(color >> 4) & 0xf,color & 0xf);
      }

   return (0);
}
 
void wait_close()
{
   ULONG class;
   USHORT code;

   if (redir_fp) {
      Delay(600);
      CloseWindow(w);
      CloseScreen(screen);
      return;
   }

   for (EVER) {
      if (message = (struct IntuiMessage *)GetMsg(w->UserPort)) {
         class = message->Class;
         code  = message->Code;
         ReplyMsg(message);
 
         if (class == CLOSEWINDOW) {
            CloseWindow(w);
            CloseScreen(screen);
            return;
         }
      }
   }
}

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 (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;

   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);
/* This routine crashes for some reason, thus it is left out
            if (class == CLOSEWINDOW) {
               CloseWindow(w);
               CloseScreen(screen);
               fclose(v_fp);
               v_fp = NULL;
               return (0);
            }                       */
         }

         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);
      }
   }
   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);
}

anal_mand()
{
   union kludge x_gap,y_gap,z_r,z_i,u_r,u_i,const0,const1,const2,const4;
   union kludge const12,temp,temp2,temp3;
   int count,x,y,width,height,last_x,last_y,select,lines;
   ULONG class;
   USHORT code;

   if (disp_mand())
      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);
   const4.i = SPFlt(4);
   const12.i = SPDiv(SPFlt(2),SPFlt(1));

   last_x = -1;
   last_y = -1;
   select = 0;
   lines = 0;

   aw.Screen = screen;
   w2 = (struct Window *)OpenWindow(&aw);
   if (w2 == NULL)
   {
      CloseWindow(w);
      CloseScreen(screen);
      fputs("Can't open analyzing window\n",console);
      return (1);
   }

   rp2 = w2->RPort;
 
   SetDrMd(rp2,JAM1);
   SetBPen(rp2, 0);

   SetAPen(rp2, 1);
   RectFill(rp2,LEFTW2+1,TOPW2+1,RIGHTW2-1,BOTTOMW2-1);

   for (EVER) {
      if (message = (struct IntuiMessage *)GetMsg(w->UserPort)) {
         class = message->Class;
         code  = message->Code;
         ReplyMsg(message);
 
         if (class == CLOSEWINDOW) {
            CloseWindow(w2);
            CloseWindow(w);
            CloseScreen(screen);
            return (0);
         }
         if (class == MOUSEBUTTONS)
            if (code == SELECTDOWN) {
               if (w->MouseY < STARTY)
                  lines = !lines;
               else
                  select = TRUE;
            }
            else if (code == SELECTUP)
               select = FALSE;
      }
      if ((last_x != w->MouseX || last_y != w->MouseY) && select &&
          w->MouseX < max_x && w->MouseY >= STARTY && w->MouseY < max_y+STARTY) {
         last_x = w-> MouseX;
         last_y = w-> MouseY;
         SetAPen(rp2,1);
         RectFill(rp2,LEFTW2+1,TOPW2+1,RIGHTW2-1,BOTTOMW2-1);
         width = RIGHTW2 - LEFTW2 - 6;
         height = BOTTOMW2 - TOPW2 - 4;
         SetAPen(rp2,3);
         Move(rp2,LEFTW2+2,TOPW2+height/2+2);
         Draw(rp2,RIGHTW2-2,TOPW2+height/2+2);
         Move(rp2,LEFTW2+width/2+3,TOPW2+2);
         Draw(rp2,LEFTW2+width/2+3,BOTTOMW2-2);
         SetAPen(rp2,2);
         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(last_x),x_gap.i));
         u_i.i = SPAdd(start_i.i,SPMul(SPFlt(max_y-(last_y-STARTY)-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++) {

            temp.i = SPDiv(const4.i,SPMul(z_r.i,SPFlt(width)));
            x = SPFix(temp.i);
            temp.i = SPDiv(const4.i,SPMul(z_i.i,SPFlt(height)));
            y = SPFix(temp.i);

            if (!lines)
               if (x != 0 || y != 0)
                  WritePixel(rp2,x+width/2+LEFTW2+3,height/2-y+TOPW2+2);
               else ;
            else
               if (count == 0)
                  Move(rp2,x+width/2+LEFTW2+3,height/2-y+TOPW2+2);
               else
                  Draw(rp2,x+width/2+LEFTW2+3,height/2-y+TOPW2+2);

            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;
            }
         }
      }
   }
}

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

   y += STARTY;

   if (!(color_mode & 1)) {
      if (color == 0)
         color = color_inset;
      else
         color = color*color_inc+color_offset;
      ham_write(*(color_table+color),x,y);
   }
   else if ((color_mode & 1) && !(color_mode & 4)) {
      if (color == 0)
         color = color_inset % 28;
      else
         color = (((color-1)/color_div+color_offset) % 28);
      SetAPen(rp,color+4);
      WritePixel(rp,x,y);
   }
   else if (color_mode & 4) {
      if (color == 0)
         color = color_inset % 12;
      else
         color = (((color-1)/color_div+color_offset) % 12);
      SetAPen(rp,color+4);
      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;
}