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 >
Wrap
C/C++ Source or Header
|
1991-08-16
|
12KB
|
562 lines
/*
* 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
*
* (C) Copyright 1989 by Olaf Seibert.
* Mandel may be freely distributed. See file 'doc/Notice' for details.
*
* The drawing task and interface code.
*
* This code MUST NOT be compiled with stack checking, since the drawing task
* has its own stack. This is also true for anything that might get called
* from here: DisableSizing(), EnableSizing(), StopFraming(), Sure(),
* EnableSystemGadgets()...
*
* It must also be linked as one of the last files before the library, so it
* is within 32K from the startup code containing geta4(). Otherwise, it
* would need a4 in order to get a4.
*/
#include <exec/types.h>
#ifndef EXEC_SEMAPHORES_H
#include <exec/semaphores.h>
#endif
#include <intuition/intuition.h>
#include "mandel.h"
#ifdef DEBUG
# include <stdio.h>
# undef STATIC
# define STATIC /* EMPTY */
#endif
extern double ReMouse,
ImMouse;
int DrawPri = 0; /* Set with SetDrawPri() */
struct Program Program[PROGRAMSIZE];
double PrgReg[2 * PROGRAMREGS];
/* Complex multiplication using pointers to reduce overhead. */
/* YOU must make sure there are no (dynamic) aliases around... */
STATIC void
MulCplx(ReRes, ImRes, ReA, ImA, ReB, ImB)
double *ReRes,
*ImRes,
*ReA,
*ImA,
*ReB,
*ImB;
{
*ReRes = *ReA * *ReB - *ImA * *ImB;
*ImRes = *ImA * *ReB + *ReA * *ImB;
}
/*
* Private cache of the RastPort to speed up drawing
*/
STATIC struct RastPort *RastPort;
/* Z^2-C: 4 multiplications per loop */
int
ZQuadMinC(ReC, ImC)
double ReC,
ImC;
{
register double ReZ = 0.0,
ImZ = 0.0;
register double ReQuad,
ImQuad;
register int Depth = -1;
while (ImQuad = ImZ * ImZ, ReQuad = ReZ * ReZ, Depth++,
(ImQuad + ReQuad < 8) && (Depth <= MaxDepth)) {
ImZ = 2 * ImZ * ReZ - ImC;
ReZ = ReQuad - ImQuad - ReC;
}
PrgReg[RE(0)] = ReZ;
PrgReg[IM(0)] = ImZ;
return Depth;
}
/* Z^2-C: 4 multiplications per loop */
int
I_ZQuadMinC(ReC, ImC)
double ReC,
ImC;
{
register double ReZ = 0.0,
ImZ = 0.0;
register double ReQuad,
ImQuad;
register int Depth = -1;
while (ImQuad = ImZ * ImZ, ReQuad = ReZ * ReZ, Depth++,
(ImQuad + ReQuad < 8) && (Depth <= MaxDepth)) {
ImZ = 2 * ImZ * ReZ - ImC;
ReZ = ReQuad - ImQuad - ReC;
PrgReg[RE(0)] = ReZ;
PrgReg[IM(0)] = ImZ;
(*IPlotFunc)();
}
PrgReg[RE(0)] = ReZ;
PrgReg[IM(0)] = ImZ;
return Depth;
}
/* Z*C*(1-Z): 10 multiplications per loop */
int
ZC1MinZ(ReC, ImC)
double ReC,
ImC;
{
#define ReZ PrgReg[RE(0)]
#define ImZ PrgReg[IM(0)]
auto double NewReZ,
NewImZ;
auto double Re1MinZ,
Im1MinZ;
register int Depth = -1;
ReZ = ReC;
ImZ = ImC;
while (Depth++, (ImZ * ImZ + ReZ * ReZ < 8) && (Depth <= MaxDepth)) {
Re1MinZ = 1 - ReZ;
Im1MinZ = -ImZ;
MulCplx(&NewReZ, &NewImZ, &ReZ, &ImZ, &ReC, &ImC);
MulCplx(&ReZ, &ImZ, &NewReZ, &NewImZ, &Re1MinZ, &Im1MinZ);
}
#undef ReZ
#undef ImZ
return Depth;
}
/* Z^3+Z*(C-1)-C: 12 multiplications per loop */
int
Z3PlusZCMin1MinC(ReC, ImC)
double ReC,
ImC;
{
#define ReZ PrgReg[RE(0)]
#define ImZ PrgReg[IM(0)]
auto double ReCMin1;
auto double ReZ2,
ImZ2,
ReZ3,
ImZ3;
register double ReQuad,
ImQuad;
register int Depth = -1;
register void (*iplot)() = IPlotFunc;
ReZ = ReC;
ImZ = ImC;
while (ImQuad = ImZ * ImZ, ReQuad = ReZ * ReZ, Depth++,
(ImQuad + ReQuad < 8) && (Depth <= MaxDepth)) {
/* Calculate z^2 */
ReZ2 = ReQuad - ImQuad;
ImZ2 = 2 * ReZ * ImZ;
/* Make z^3 */
MulCplx(&ReZ3, &ImZ3, &ReZ2, &ImZ2, &ReZ, &ImZ);
/* Calculate z(c-1) while destroying z^2 */
ReCMin1 = ReC - 1;
MulCplx(&ReZ2, &ImZ2, &ReZ, &ImZ, &ReCMin1, &ImC);
/* Add everything */
ReZ = ReZ3 + ReZ2 - ReC;
ImZ = ImZ3 + ImZ2 - ImC;
}
#undef ReZ
#undef ImZ
return Depth;
}
/*
* User programmed function...
*/
int
UserProgFunc(ReC, ImC)
double ReC,
ImC;
{
register struct Program *pc;
register struct Program *MainPC;
register int Depth = -1;
register int pr_Dest;
register void (*iplot)() = IPlotFunc;
PrgReg[RE(2)] = ReC;
PrgReg[IM(2)] = ImC;
PrgReg[RE(3)] = ReMouse;
PrgReg[IM(3)] = ImMouse;
#define ReZ PrgReg[RE(0)]
#define ImZ PrgReg[IM(0)]
#define ReQuad PrgReg[RE(1)]
#define ImQuad PrgReg[IM(1)]
#define ReC PrgReg[RE(2)]
#define ImC PrgReg[IM(2)]
ReZ = 0.0;
ImZ = 0.0;
/* Do the prelude: */
pc = &Program[0];
goto InterpretLoop; /* I know this is ugly */
PreludeDone:
MainPC = pc + 1;
while (ImQuad = ImZ * ImZ, ReQuad = ReZ * ReZ, Depth++,
(ImQuad + ReQuad < 8) && (Depth <= MaxDepth)) {
pc = MainPC;
InterpretLoop:
for (;;) {
pr_Dest = pc->pr_Dest;
switch (pc->pr_OpCode) {
case End:
if (pr_Dest) /* == 1 */
goto EndOfProgram;
else
goto PreludeDone;
case Cassign:
PrgReg[IM(pr_Dest)] = PrgReg[IM(pc->pr_Op1)];
case Rassign:
PrgReg[RE(pr_Dest)] = PrgReg[RE(pc->pr_Op1)];
break;
case Ci:
PrgReg[IM(pr_Dest)] = (double) pc->pr_Op2;
case Ri:
PrgReg[RE(pr_Dest)] = (double) pc->pr_Op1;
break;
case Cplus:
PrgReg[IM(pr_Dest)] = PrgReg[IM(pc->pr_Op1)] +
PrgReg[IM(pc->pr_Op2)];
case Rplus:
PrgReg[RE(pr_Dest)] = PrgReg[RE(pc->pr_Op1)] +
PrgReg[RE(pc->pr_Op2)];
break;
case Cminus:
PrgReg[IM(pr_Dest)] = PrgReg[IM(pc->pr_Op1)] -
PrgReg[IM(pc->pr_Op2)];
case Rminus:
PrgReg[RE(pr_Dest)] = PrgReg[RE(pc->pr_Op1)] -
PrgReg[RE(pc->pr_Op2)];
break;
case Ctimes:
MulCplx(
&PrgReg[RE(pr_Dest)], &PrgReg[IM(pr_Dest)],
&PrgReg[RE(pc->pr_Op1)], &PrgReg[IM(pc->pr_Op1)],
&PrgReg[RE(pc->pr_Op2)], &PrgReg[IM(pc->pr_Op2)]
);
break;
case Rtimes:
PrgReg[RE(pr_Dest)] = PrgReg[RE(pc->pr_Op1)] *
PrgReg[RE(pc->pr_Op2)];
break;
} /* end of switch */
pc++;
} /* end of for */
EndOfProgram:
(*iplot)();
} /* end of while */
return Depth;
#undef ReZ
#undef ImZ
#undef ReQuad
#undef ImQuad
#undef ReC
#undef ImC
}
void PlotIterationCount(Count, x, y)
register int Count;
long x,
y;
{
if (Count > MaxDepth)
Count = PenTable[0];
else
Count = PenTable[Count];
if (RastPort->FgPen != (BYTE) Count)
SetAPen(RastPort, (long) Count);
WritePixel(RastPort, x, y);
}
void PlotZ()
{
register int Color;
register long x,
y;
x = (PrgReg[RE(0)] - LeftEdge) / CXStep;
y = (TopEdge - PrgReg[IM(0)]) / CYStep;
/*
* Color will be -1 + 1 if we are within the window
*/
if (Color = ReadPixel(RastPort, x, y) + 1) {
if (RastPort->FgPen != (BYTE) Color)
SetAPen(RastPort, (long) Color);
WritePixel(RastPort, x, y);
}
}
void None()
{
/* empty */
}
/* Some private variables */
struct Task *DrawTask = NULL;
struct Task *MandelTask = NULL;
struct SignalSemaphore DrawSemaphore;
/*
* This is what it is all about!
*/
STATIC bool MyFillIn; /* Parameter for new task */
STATIC void
ActuallyDrawPicture()
{
double x, /* Running Real value */
y, /* Running Imaginary value */
Leftx; /* Reset Real value */
register long px, /* Running horizontal pixel coordinate */
py; /* Running vertical pixel coordinate */
long Leftpx, /* Reset horizontal pixel coordinate */
minpx; /* Minimal horizontal pixel coordinate */
register long maxpx; /* Maximal horizontal pixel coordinate */
long minpy, /* Minimal vertical pixel coordinate */
maxpy; /* Maximal vertical pixel coordinate */
double MyXstep, /* Real increment */
MyYstep; /* Imaginary increment */
int MyPixelStep,/* Private copy of PixelStep */
XOffset, /* Running from 0 to MyPixelStep */
YOffset; /* Running from 0 to MyPixelStep */
struct Library *MathBasBase;/* Pointer to mathxxx.library */
register int (*Function) ();
register void (*Plot) ();
geta4(); /* Manx small memory model */
ObtainSemaphore(&DrawSemaphore);
#ifdef IEEEDP
/*
* We must open this library ourselves, just in case we have a math
* chip that needs extra context saving to be done. But to really
* access the library, we use the global library base that the main
* task has set for us. (but they are the same, anyway)
*/
MathBasBase = OpenLibrary("mathieeedoubbas.library", LIBRARY_VERSION);
#else
MathBasBase = OpenLibrary("mathffp.library", LIBRARY_VERSION);
#endif
StillDrawing = TRUE;
DisableSizing();
StopFraming();
OffMenu(MainWindow, (ULONG) SHIFTMENU(PRJMENU) | SHIFTITEM(PRJNEW) |
SHIFTSUB(NOSUB));
OffMenu(MainWindow, (ULONG) SHIFTMENU(OPTMENU) | SHIFTITEM(OPTRES) |
SHIFTSUB(ORFIL));
if (!MyFillIn && !Sure())
skipto exit;
if (!MyFillIn)
NameValid = FALSE;
Saved = FALSE;
MyPixelStep = PixelStep;
XOffset = 0;
YOffset = MyFillIn ? 1 : 0;
minpx = 0;
maxpx = MainWindow->GZZWidth - 1;
minpy = 0;
maxpy = MainWindow->GZZHeight - 1;
RastPort = MainWindow->RPort;
SetDrMd(RastPort, (long) JAM1);
if (!MyFillIn) { /* Clear the window */
SetAPen(RastPort, (long) 2); /* was PenTable[0] */
RectFill(RastPort, minpx, minpy, maxpx, maxpy);
}
CalcCSteps(); /* Calculate CXStep and CYStep */
MyXstep = MyPixelStep * CXStep;
MyYstep = MyPixelStep * CYStep;
Function = DepthFunc;
Plot = EPlotFunc;
ReleaseSemaphore(&DrawSemaphore);
again:
Leftpx = minpx + XOffset; /* Start in the upper left-hand corner */
py = minpy + YOffset; /* of the window */
Leftx = LeftEdge + XOffset * CXStep;
y = TopEdge - YOffset * CYStep;
for (; py <= maxpy; y -= MyYstep, py += MyPixelStep) {
ObtainSemaphore(&DrawSemaphore);
for (px = Leftpx, x = Leftx; px <= maxpx; x += MyXstep, px += MyPixelStep) {
(*Plot) ((*Function) (x, y), px, py);
/* Check if we are asked to terminate. release s'phore. */
if (StillDrawing < 0) {
ReleaseSemaphore(&DrawSemaphore);
skipto exit;
}
}
ReleaseSemaphore(&DrawSemaphore);
}
if (MyFillIn && (++YOffset < MyPixelStep)) {
backto again; /* Draw pixels below current pixel */
}
if (MyFillIn && (++XOffset < MyPixelStep)) {
YOffset = 0; /* and next to them */
backto again;
}
exit:
ObtainSemaphore(&DrawSemaphore);
if (MathBasBase)
CloseLibrary(MathBasBase);
EnableSizing();
OnMenu(MainWindow, (ULONG) SHIFTMENU(PRJMENU) | SHIFTITEM(PRJNEW) |
SHIFTSUB(NOSUB));
OnMenu(MainWindow, (ULONG) SHIFTMENU(OPTMENU) | SHIFTITEM(OPTRES) |
SHIFTSUB(ORFIL));
DrawTask = NULL;
StillDrawing = FALSE; /* We are finished, finally... */
ReleaseSemaphore(&DrawSemaphore);
Signal(MandelTask, DrawSigMask); /* and shout it off the roof */
}
bool
DrawPicture(FillIn)
bool FillIn;
{
register long Priority;
if (StillDrawing == FALSE) {
Priority = MandelTask->tc_Node.ln_Pri + DrawPri;
MyFillIn = FillIn;
SetSignal(0L, DrawSigMask); /* Clear the drawing signal */
DrawTask = CreateTask("Mandelbrot_Drawing.task", Priority,
ActuallyDrawPicture, 2048L);
}
return DrawTask != NULL;
}
/* Interface because I wanted to CreateTask the drawing... */
void
WaitForDrawing()
{
Forbid();
if (StillDrawing)
Wait(DrawSigMask);
Permit();
}
void
StopDrawing()
{
Forbid();
if (StillDrawing) {
StillDrawing = -1; /* Indicate termination is wanted. */
WaitForDrawing(); /* Clears the draw/batch signal. */
} /* Bug or feature? Need Batch/Cont. */
Permit();
}
void
SetDrawPri(Priority)
int Priority;
{
DrawPri = Priority;
Forbid();
if (StillDrawing) {
Priority = MandelTask->tc_Node.ln_Pri + DrawPri;
SetTaskPri(DrawTask, (long) Priority);
}
Permit();
}
/*
* This is the external interface to the DrawSemaphore. Use it with care.
* Always balance calls to SuspendDrawing() with ResumeDrawing() !!!
*/
void
SuspendDrawing()
{
ObtainSemaphore(&DrawSemaphore);
}
void
ResumeDrawing()
{
ReleaseSemaphore(&DrawSemaphore);
}
void
CalcCSteps()
{
CXStep = (double) (RightEdge - LeftEdge) / (MainWindow->GZZWidth - 1);
CYStep = (double) (TopEdge - BottomEdge) / (MainWindow->GZZHeight - 1);
}