home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / fract / mandel.lzh / MANDEL / SRC / DRAW.C < prev    next >
C/C++ Source or Header  |  1991-08-16  |  12KB  |  562 lines

  1. /*
  2.  * M A N D E L B R O T       C O N S T R U C T I O N   S E T
  3.  *
  4.  * (C) Copyright 1989 by Olaf Seibert.
  5.  * Mandel may be freely distributed. See file 'doc/Notice' for details.
  6.  *
  7.  * The drawing task and interface code.
  8.  *
  9.  * This code MUST NOT be compiled with stack checking, since the drawing task
  10.  * has its own stack. This is also true for anything that might get called
  11.  * from here: DisableSizing(), EnableSizing(), StopFraming(), Sure(),
  12.  * EnableSystemGadgets()...
  13.  *
  14.  * It must also be linked as one of the last files before the library, so it
  15.  * is within 32K from the startup code containing geta4(). Otherwise, it
  16.  * would need a4 in order to get a4.
  17.  */
  18.  
  19. #include <exec/types.h>
  20. #ifndef EXEC_SEMAPHORES_H
  21. #include <exec/semaphores.h>
  22. #endif
  23. #include <intuition/intuition.h>
  24. #include "mandel.h"
  25. #ifdef DEBUG
  26. #   include <stdio.h>
  27. #   undef STATIC
  28. #   define STATIC        /* EMPTY */
  29. #endif
  30.  
  31. extern double    ReMouse,
  32.         ImMouse;
  33.  
  34. int        DrawPri = 0;    /* Set with SetDrawPri() */
  35.  
  36. struct Program    Program[PROGRAMSIZE];
  37. double        PrgReg[2 * PROGRAMREGS];
  38.  
  39. /* Complex multiplication using pointers to reduce overhead.   */
  40. /* YOU must make sure there are no (dynamic) aliases around... */
  41.  
  42. STATIC void
  43. MulCplx(ReRes, ImRes, ReA, ImA, ReB, ImB)
  44. double           *ReRes,
  45.            *ImRes,
  46.            *ReA,
  47.            *ImA,
  48.            *ReB,
  49.            *ImB;
  50. {
  51.     *ReRes = *ReA * *ReB - *ImA * *ImB;
  52.     *ImRes = *ImA * *ReB + *ReA * *ImB;
  53. }
  54.  
  55. /*
  56.  * Private cache of the RastPort to speed up drawing
  57.  */
  58.  
  59. STATIC struct RastPort *RastPort;
  60.  
  61. /* Z^2-C: 4 multiplications per loop */
  62.  
  63. int
  64. ZQuadMinC(ReC, ImC)
  65. double        ReC,
  66.         ImC;
  67. {
  68.     register double ReZ = 0.0,
  69.             ImZ = 0.0;
  70.     register double ReQuad,
  71.             ImQuad;
  72.     register int    Depth = -1;
  73.  
  74.     while (ImQuad = ImZ * ImZ, ReQuad = ReZ * ReZ, Depth++,
  75.        (ImQuad + ReQuad < 8) && (Depth <= MaxDepth)) {
  76.     ImZ = 2 * ImZ * ReZ - ImC;
  77.     ReZ = ReQuad - ImQuad - ReC;
  78.     }
  79.  
  80.     PrgReg[RE(0)] = ReZ;
  81.     PrgReg[IM(0)] = ImZ;
  82.  
  83.     return Depth;
  84. }
  85.  
  86. /* Z^2-C: 4 multiplications per loop */
  87.  
  88. int
  89. I_ZQuadMinC(ReC, ImC)
  90. double        ReC,
  91.         ImC;
  92. {
  93.     register double ReZ = 0.0,
  94.             ImZ = 0.0;
  95.     register double ReQuad,
  96.             ImQuad;
  97.     register int    Depth = -1;
  98.  
  99.     while (ImQuad = ImZ * ImZ, ReQuad = ReZ * ReZ, Depth++,
  100.        (ImQuad + ReQuad < 8) && (Depth <= MaxDepth)) {
  101.     ImZ = 2 * ImZ * ReZ - ImC;
  102.     ReZ = ReQuad - ImQuad - ReC;
  103.  
  104.     PrgReg[RE(0)] = ReZ;
  105.     PrgReg[IM(0)] = ImZ;
  106.  
  107.     (*IPlotFunc)();
  108.     }
  109.  
  110.     PrgReg[RE(0)] = ReZ;
  111.     PrgReg[IM(0)] = ImZ;
  112.  
  113.     return Depth;
  114. }
  115.  
  116. /* Z*C*(1-Z): 10 multiplications per loop */
  117.  
  118. int
  119. ZC1MinZ(ReC, ImC)
  120. double        ReC,
  121.         ImC;
  122. {
  123. #define ReZ    PrgReg[RE(0)]
  124. #define ImZ    PrgReg[IM(0)]
  125.     auto double     NewReZ,
  126.             NewImZ;
  127.     auto double     Re1MinZ,
  128.             Im1MinZ;
  129.     register int    Depth = -1;
  130.  
  131.     ReZ = ReC;
  132.     ImZ = ImC;
  133.  
  134.     while (Depth++, (ImZ * ImZ + ReZ * ReZ < 8) && (Depth <= MaxDepth)) {
  135.     Re1MinZ = 1 - ReZ;
  136.     Im1MinZ = -ImZ;
  137.     MulCplx(&NewReZ, &NewImZ, &ReZ, &ImZ, &ReC, &ImC);
  138.     MulCplx(&ReZ, &ImZ, &NewReZ, &NewImZ, &Re1MinZ, &Im1MinZ);
  139.     }
  140.  
  141. #undef ReZ
  142. #undef ImZ
  143.  
  144.     return Depth;
  145. }
  146.  
  147. /* Z^3+Z*(C-1)-C: 12 multiplications per loop */
  148.  
  149. int
  150. Z3PlusZCMin1MinC(ReC, ImC)
  151. double        ReC,
  152.         ImC;
  153. {
  154. #define ReZ    PrgReg[RE(0)]
  155. #define ImZ    PrgReg[IM(0)]
  156.     auto double     ReCMin1;
  157.     auto double     ReZ2,
  158.             ImZ2,
  159.             ReZ3,
  160.             ImZ3;
  161.     register double ReQuad,
  162.             ImQuad;
  163.     register int    Depth = -1;
  164.     register void (*iplot)() = IPlotFunc;
  165.  
  166.     ReZ = ReC;
  167.     ImZ = ImC;
  168.  
  169.     while (ImQuad = ImZ * ImZ, ReQuad = ReZ * ReZ, Depth++,
  170.        (ImQuad + ReQuad < 8) && (Depth <= MaxDepth)) {
  171.     /* Calculate z^2 */
  172.     ReZ2 = ReQuad - ImQuad;
  173.     ImZ2 = 2 * ReZ * ImZ;
  174.  
  175.     /* Make z^3 */
  176.     MulCplx(&ReZ3, &ImZ3, &ReZ2, &ImZ2, &ReZ, &ImZ);
  177.  
  178.     /* Calculate z(c-1) while destroying z^2 */
  179.     ReCMin1 = ReC - 1;
  180.     MulCplx(&ReZ2, &ImZ2, &ReZ, &ImZ, &ReCMin1, &ImC);
  181.  
  182.     /* Add everything */
  183.     ReZ = ReZ3 + ReZ2 - ReC;
  184.     ImZ = ImZ3 + ImZ2 - ImC;
  185.     }
  186.  
  187. #undef ReZ
  188. #undef ImZ
  189.  
  190.     return Depth;
  191. }
  192.  
  193. /*
  194.  * User programmed function...
  195.  */
  196.  
  197. int
  198. UserProgFunc(ReC, ImC)
  199. double        ReC,
  200.         ImC;
  201. {
  202.     register struct Program *pc;
  203.     register struct Program *MainPC;
  204.     register int    Depth = -1;
  205.     register int    pr_Dest;
  206.     register void (*iplot)() = IPlotFunc;
  207.  
  208.     PrgReg[RE(2)] = ReC;
  209.     PrgReg[IM(2)] = ImC;
  210.  
  211.     PrgReg[RE(3)] = ReMouse;
  212.     PrgReg[IM(3)] = ImMouse;
  213.  
  214. #define ReZ    PrgReg[RE(0)]
  215. #define ImZ    PrgReg[IM(0)]
  216.  
  217. #define ReQuad    PrgReg[RE(1)]
  218. #define ImQuad    PrgReg[IM(1)]
  219.  
  220. #define ReC    PrgReg[RE(2)]
  221. #define ImC    PrgReg[IM(2)]
  222.  
  223.     ReZ = 0.0;
  224.     ImZ = 0.0;
  225.  
  226.     /* Do the prelude: */
  227.     pc = &Program[0];
  228.     goto InterpretLoop;     /* I know this is ugly */
  229. PreludeDone:
  230.     MainPC = pc + 1;
  231.  
  232.     while (ImQuad = ImZ * ImZ, ReQuad = ReZ * ReZ, Depth++,
  233.        (ImQuad + ReQuad < 8) && (Depth <= MaxDepth)) {
  234.     pc = MainPC;
  235. InterpretLoop:
  236.     for (;;) {
  237.         pr_Dest = pc->pr_Dest;
  238.  
  239.         switch (pc->pr_OpCode) {
  240.         case End:
  241.         if (pr_Dest)    /* == 1 */
  242.             goto EndOfProgram;
  243.         else
  244.             goto PreludeDone;
  245.  
  246.         case Cassign:
  247.         PrgReg[IM(pr_Dest)] = PrgReg[IM(pc->pr_Op1)];
  248.         case Rassign:
  249.         PrgReg[RE(pr_Dest)] = PrgReg[RE(pc->pr_Op1)];
  250.         break;
  251.  
  252.         case Ci:
  253.         PrgReg[IM(pr_Dest)] = (double) pc->pr_Op2;
  254.         case Ri:
  255.         PrgReg[RE(pr_Dest)] = (double) pc->pr_Op1;
  256.         break;
  257.  
  258.         case Cplus:
  259.         PrgReg[IM(pr_Dest)] = PrgReg[IM(pc->pr_Op1)] +
  260.             PrgReg[IM(pc->pr_Op2)];
  261.         case Rplus:
  262.         PrgReg[RE(pr_Dest)] = PrgReg[RE(pc->pr_Op1)] +
  263.             PrgReg[RE(pc->pr_Op2)];
  264.         break;
  265.  
  266.         case Cminus:
  267.         PrgReg[IM(pr_Dest)] = PrgReg[IM(pc->pr_Op1)] -
  268.             PrgReg[IM(pc->pr_Op2)];
  269.         case Rminus:
  270.         PrgReg[RE(pr_Dest)] = PrgReg[RE(pc->pr_Op1)] -
  271.             PrgReg[RE(pc->pr_Op2)];
  272.         break;
  273.  
  274.         case Ctimes:
  275.         MulCplx(
  276.             &PrgReg[RE(pr_Dest)], &PrgReg[IM(pr_Dest)],
  277.             &PrgReg[RE(pc->pr_Op1)], &PrgReg[IM(pc->pr_Op1)],
  278.             &PrgReg[RE(pc->pr_Op2)], &PrgReg[IM(pc->pr_Op2)]
  279.             );
  280.         break;
  281.  
  282.         case Rtimes:
  283.         PrgReg[RE(pr_Dest)] = PrgReg[RE(pc->pr_Op1)] *
  284.             PrgReg[RE(pc->pr_Op2)];
  285.         break;
  286.         }            /* end of switch */
  287.         pc++;
  288.     }            /* end of for */
  289. EndOfProgram:
  290.     (*iplot)();
  291.     }                /* end of while */
  292.  
  293.     return Depth;
  294.  
  295. #undef ReZ
  296. #undef ImZ
  297.  
  298. #undef ReQuad
  299. #undef ImQuad
  300.  
  301. #undef ReC
  302. #undef ImC
  303.  
  304. }
  305.  
  306. void PlotIterationCount(Count, x, y)
  307. register int    Count;
  308. long        x,
  309.         y;
  310. {
  311.     if (Count > MaxDepth)
  312.     Count = PenTable[0];
  313.     else
  314.     Count = PenTable[Count];
  315.  
  316.     if (RastPort->FgPen != (BYTE) Count)
  317.     SetAPen(RastPort, (long) Count);
  318.     WritePixel(RastPort, x, y);
  319. }
  320.  
  321. void PlotZ()
  322. {
  323.     register int    Color;
  324.     register long   x,
  325.             y;
  326.  
  327.     x = (PrgReg[RE(0)] - LeftEdge) / CXStep;
  328.     y = (TopEdge -  PrgReg[IM(0)]) / CYStep;
  329.  
  330.     /*
  331.      * Color will be -1 + 1 if we are within the window
  332.      */
  333.  
  334.     if (Color = ReadPixel(RastPort, x, y) + 1) {
  335.     if (RastPort->FgPen != (BYTE) Color)
  336.         SetAPen(RastPort, (long) Color);
  337.     WritePixel(RastPort, x, y);
  338.     }
  339. }
  340.  
  341. void None()
  342. {
  343.     /* empty */
  344. }
  345.  
  346. /* Some private variables */
  347.  
  348. struct Task    *DrawTask = NULL;
  349. struct Task    *MandelTask = NULL;
  350. struct SignalSemaphore DrawSemaphore;
  351.  
  352.  
  353. /*
  354.  * This is what it is all about!
  355.  */
  356.  
  357. STATIC bool    MyFillIn;    /* Parameter for new task */
  358.  
  359. STATIC void
  360. ActuallyDrawPicture()
  361. {
  362.     double        x,        /* Running Real value */
  363.             y,        /* Running Imaginary value */
  364.             Leftx;    /* Reset Real value */
  365.     register long   px,     /* Running horizontal pixel coordinate */
  366.             py;     /* Running vertical pixel coordinate */
  367.  
  368.     long        Leftpx,    /* Reset horizontal pixel coordinate */
  369.             minpx;    /* Minimal horizontal pixel coordinate */
  370.     register long   maxpx;    /* Maximal horizontal pixel coordinate */
  371.     long        minpy,    /* Minimal vertical pixel coordinate */
  372.             maxpy;    /* Maximal vertical pixel coordinate */
  373.     double        MyXstep,    /* Real increment */
  374.             MyYstep;    /* Imaginary increment */
  375.     int         MyPixelStep,/* Private copy of PixelStep */
  376.             XOffset,    /* Running from 0 to MyPixelStep */
  377.             YOffset;    /* Running from 0 to MyPixelStep */
  378.     struct Library *MathBasBase;/* Pointer to mathxxx.library */
  379.  
  380.     register int    (*Function) ();
  381.     register void   (*Plot) ();
  382.  
  383.     geta4();                    /* Manx small memory model */
  384.  
  385.     ObtainSemaphore(&DrawSemaphore);
  386.  
  387. #ifdef IEEEDP
  388.     /*
  389.      * We must open this library ourselves, just in case we have a math
  390.      * chip that needs extra context saving to be done. But to really
  391.      * access the library, we use the global library base that the main
  392.      * task has set for us. (but they are the same, anyway)
  393.      */
  394.     MathBasBase = OpenLibrary("mathieeedoubbas.library", LIBRARY_VERSION);
  395. #else
  396.     MathBasBase = OpenLibrary("mathffp.library", LIBRARY_VERSION);
  397. #endif
  398.  
  399.     StillDrawing = TRUE;
  400.     DisableSizing();
  401.     StopFraming();
  402.     OffMenu(MainWindow, (ULONG) SHIFTMENU(PRJMENU) | SHIFTITEM(PRJNEW) |
  403.         SHIFTSUB(NOSUB));
  404.     OffMenu(MainWindow, (ULONG) SHIFTMENU(OPTMENU) | SHIFTITEM(OPTRES) |
  405.         SHIFTSUB(ORFIL));
  406.  
  407.     if (!MyFillIn && !Sure())
  408.     skipto        exit;
  409.  
  410.     if (!MyFillIn)
  411.     NameValid = FALSE;
  412.     Saved = FALSE;
  413.     MyPixelStep = PixelStep;
  414.     XOffset = 0;
  415.     YOffset = MyFillIn ? 1 : 0;
  416.  
  417.     minpx = 0;
  418.     maxpx = MainWindow->GZZWidth - 1;
  419.     minpy = 0;
  420.     maxpy = MainWindow->GZZHeight - 1;
  421.  
  422.     RastPort = MainWindow->RPort;
  423.     SetDrMd(RastPort, (long) JAM1);
  424.  
  425.     if (!MyFillIn) {            /* Clear the window */
  426.     SetAPen(RastPort, (long) 2);    /* was PenTable[0] */
  427.     RectFill(RastPort, minpx, minpy, maxpx, maxpy);
  428.     }
  429.     CalcCSteps();               /* Calculate CXStep and CYStep */
  430.  
  431.     MyXstep = MyPixelStep * CXStep;
  432.     MyYstep = MyPixelStep * CYStep;
  433.  
  434.     Function = DepthFunc;
  435.     Plot = EPlotFunc;
  436.  
  437.     ReleaseSemaphore(&DrawSemaphore);
  438.  
  439. again:
  440.     Leftpx = minpx + XOffset;    /* Start in the upper left-hand corner */
  441.     py = minpy + YOffset;    /* of the window */
  442.     Leftx = LeftEdge + XOffset * CXStep;
  443.     y = TopEdge - YOffset * CYStep;
  444.  
  445.     for (; py <= maxpy; y -= MyYstep, py += MyPixelStep) {
  446.     ObtainSemaphore(&DrawSemaphore);
  447.     for (px = Leftpx, x = Leftx; px <= maxpx; x += MyXstep, px += MyPixelStep) {
  448.         (*Plot) ((*Function) (x, y), px, py);
  449.         /* Check if we are asked to terminate. release s'phore. */
  450.         if (StillDrawing < 0) {
  451.         ReleaseSemaphore(&DrawSemaphore);
  452.         skipto        exit;
  453.         }
  454.     }
  455.     ReleaseSemaphore(&DrawSemaphore);
  456.     }
  457.  
  458.     if (MyFillIn && (++YOffset < MyPixelStep)) {
  459.     backto        again;    /* Draw pixels below current pixel */
  460.     }
  461.     if (MyFillIn && (++XOffset < MyPixelStep)) {
  462.     YOffset = 0;        /* and next to them */
  463.     backto        again;
  464.     }
  465. exit:
  466.     ObtainSemaphore(&DrawSemaphore);
  467.     if (MathBasBase)
  468.     CloseLibrary(MathBasBase);
  469.     EnableSizing();
  470.     OnMenu(MainWindow, (ULONG) SHIFTMENU(PRJMENU) | SHIFTITEM(PRJNEW) |
  471.        SHIFTSUB(NOSUB));
  472.     OnMenu(MainWindow, (ULONG) SHIFTMENU(OPTMENU) | SHIFTITEM(OPTRES) |
  473.        SHIFTSUB(ORFIL));
  474.     DrawTask = NULL;
  475.     StillDrawing = FALSE;    /* We are finished, finally... */
  476.     ReleaseSemaphore(&DrawSemaphore);
  477.  
  478.     Signal(MandelTask, DrawSigMask);    /* and shout it off the roof */
  479. }
  480.  
  481. bool
  482. DrawPicture(FillIn)
  483. bool        FillIn;
  484. {
  485.     register long   Priority;
  486.  
  487.     if (StillDrawing == FALSE) {
  488.     Priority = MandelTask->tc_Node.ln_Pri + DrawPri;
  489.     MyFillIn = FillIn;
  490.  
  491.     SetSignal(0L, DrawSigMask);     /* Clear the drawing signal */
  492.  
  493.     DrawTask = CreateTask("Mandelbrot_Drawing.task", Priority,
  494.                   ActuallyDrawPicture, 2048L);
  495.     }
  496.     return DrawTask != NULL;
  497. }
  498.  
  499. /* Interface because I wanted to CreateTask the drawing... */
  500.  
  501. void
  502. WaitForDrawing()
  503. {
  504.     Forbid();
  505.  
  506.     if (StillDrawing)
  507.     Wait(DrawSigMask);
  508.  
  509.     Permit();
  510. }
  511.  
  512. void
  513. StopDrawing()
  514. {
  515.     Forbid();
  516.  
  517.     if (StillDrawing) {
  518.     StillDrawing = -1;    /* Indicate termination is wanted.  */
  519.     WaitForDrawing();       /* Clears the draw/batch signal.    */
  520.     }                /* Bug or feature? Need Batch/Cont. */
  521.     Permit();
  522. }
  523.  
  524. void
  525. SetDrawPri(Priority)
  526. int        Priority;
  527. {
  528.     DrawPri = Priority;
  529.  
  530.     Forbid();
  531.  
  532.     if (StillDrawing) {
  533.     Priority = MandelTask->tc_Node.ln_Pri + DrawPri;
  534.     SetTaskPri(DrawTask, (long) Priority);
  535.     }
  536.     Permit();
  537. }
  538.  
  539. /*
  540.  * This is the external interface to the DrawSemaphore. Use it with care.
  541.  * Always balance calls to SuspendDrawing() with ResumeDrawing() !!!
  542.  */
  543.  
  544. void
  545. SuspendDrawing()
  546. {
  547.     ObtainSemaphore(&DrawSemaphore);
  548. }
  549.  
  550. void
  551. ResumeDrawing()
  552. {
  553.     ReleaseSemaphore(&DrawSemaphore);
  554. }
  555.  
  556. void
  557. CalcCSteps()
  558. {
  559.     CXStep = (double) (RightEdge - LeftEdge) / (MainWindow->GZZWidth - 1);
  560.     CYStep = (double) (TopEdge - BottomEdge) / (MainWindow->GZZHeight - 1);
  561. }
  562.