Mandelbrot v1 for Amiga in C

 
This is the C version of the Mandelbrot v1 program, originally written in assembler. It is provided here for comparison. It produces exactly the same picture as the ASM version, and the functions correspond directly to those described in the assembler version. The only difference is that a small optimization - multiplying by 2.0 - is not used in the outermost loop of the calculation, as it would only make the C source harder to read and bring very limited benefit (as seen on the line 069). On the other hand, in the innermost loop it brings a significant benefit, as it eliminates one of four multiplications. The implementation of this optimization can be found lines 063 and 082. The principle is explained in the ASM source description.

The program was compiled using SAS/C 5.10. It should be compiled like this (content of CMandelbrot_v1.build file):

LC -b1 -cfist -ff -O -v -y CMandelbrot_V1.c
BLink FROM LIB:c.o,CMandelbrot_v1.o LIB:lcmffp.lib,LIB:Amiga.lib,LIB:lc.lib
TO CMandelbrot_v1 DEFINE __main=__tinymain

The C source for SAS/C 5.10, the build script, the Amiga executable, and the icons (from SAS/C) can be downloaded here.
 
001  #define APP_WIDTH  320
002  #define APP_HEIGHT 121
003  #define MAX_ITER    75
004
005  #include <exec/types.h>
006  #include <exec/ports.h>
007  #include <graphics/rastport.h>
008  #include <graphics/gfxbase.h>
009  #include <intuition/intuitionbase.h>
010  #include <libraries/dos.h>
011  #include <proto/all.h>
012
013  struct GfxBase *GfxBase = NULL;
014  struct IntuitionBase *IntuitionBase = NULL;
015
016  struct Window *window = NULL;
017  struct RastPort *rastport;
018  USHORT borderleft, bordertop;
019
020  int GetReplyMsg(void)
021  {
022     struct IntuiMessage *intuiMessage;
023
024     intuiMessage = (struct IntuiMessage *)GetMsg(window->UserPort);
025     if (intuiMessage)
026        ReplyMsg((struct Message *)intuiMessage);
027
028     return (int)intuiMessage;
029  }
030
031  void ExecWait(void)
032  {
033     Wait(1 << window->UserPort->mp_SigBit);
034     GetReplyMsg();
035  }
036
037  struct NewWindow nw =
038  {
039     100, 20, APP_WIDTH, APP_HEIGHT, -1, -1, CLOSEWINDOW | NEWSIZE,
040     WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SMART_REFRESH | ACTIVATE,
041     NULL, NULL, "CMandelbrot v1", NULL, NULL, 100, 20, 640, 200,
042     WBENCHSCREEN
043  };
044
045  USHORT GetPointColor(USHORT iter)
046  {
047     if (iter == MAX_ITER)
048        return 0;
049   
050     return iter % 3 + 1;
051  }
052
053  void DrawPoint(USHORT x, USHORT y, USHORT color)
054  {
055     SetAPen(rastport, color);
056     WritePixel(rastport, x + borderleft, y + bordertop);
057  }
058
059  void CalcMandelbrot(void)
060  {
061     float  xstep, cr, ci, zr, zi, zr2, zi2;
062     USHORT pos_x, pos_y, iter;
063     UBYTE  *p_zr = ((UBYTE *) &zr) + 3; /* pointer to the exponent of zr */
064
065     xstep = 3.0 / (float)APP_WIDTH;
066
067     for (pos_y = 0; pos_y < APP_HEIGHT; pos_y++)
068     {
069        ci = 2.0 * pos_y * xstep - 1.125; /* optimization is not used here */
070        for (pos_x = 0; pos_x < APP_WIDTH; pos_x++)
071        {
072           cr = pos_x * xstep - 2.25;
073
074           iter = 1;
075           zr = cr;
076           zi = ci;
077           do
078           {
079              zr2 = zr * zr;
080              zi2 = zi * zi;
081              if (zr2 + zi2 >= 4.0) break;
082              (*p_zr)++; /* zr *= 2.0; */
083              zi = zr * zi + ci;
084              zr = zr2 - zi2 + cr;
085              iter++;
086           } while (iter != MAX_ITER);
087           DrawPoint(pos_x, pos_y, GetPointColor(iter));
088           if (GetReplyMsg()) return;
089        }
090     }
091     ExecWait();
092  }
093
094  int main(int argc, char *argv[])
095  {
096     int exitval = RETURN_ERROR;
097   
098     IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",
099                      0L);
100     if (!IntuitionBase) goto fini;
101
102     GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L);
103     if (!GfxBase) goto fini;
104
105     window = OpenWindow(&nw);
106     if (!window) goto fini;
107   
108     exitval = RETURN_OK;
109
110     borderleft = window->BorderLeft;
111     bordertop = window->BorderTop;
112     rastport = window->RPort;
113     SizeWindow(window, borderleft + window->BorderRight,
114                        bordertop + window->BorderBottom);
115     ExecWait();
116
117     CalcMandelbrot();
118   
119  fini:
120     if (window) CloseWindow(window);
121     if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
122     if (GfxBase) CloseLibrary((struct Library *)GfxBase);
123
124     return exitval;
125  }