-- Kaleidoscope.mesa
-- Last Edited
-- Gobbel 28-Feb-82 16:39:08
-- Yamamoto 19-Sep-83 10:08:58
-- Copyright (C) 1984 by Xerox Corporation. All rights reserved.
DIRECTORY
Display USING [Bitmap, Black, replaceFlags],
Environment USING [bitsPerWord, wordsPerPage],
Exec USING [AddCommand, ExecProc],
Heap USING [Create],
Inline USING [BITAND, BITSHIFT, BITXOR, LongCOPY],
Mopcodes USING [zLI4, zSHIFT, zWLFS],
MSegment USING [Address, Create, Handle],
Process USING [Abort, Detach, DisableTimeout, EnableAborts,
priorityBackground, priorityNormal, SecondsToTicks, SetPriority, Yield],
Profile USING [initialToolStateDefault],
ToolWindow USING [Activate, AdjustProcType, Box, Create,
CreateSubwindow, Deactivate, Show, TransitionProcType],
UserInput USING [AttentionProcType, ClearInputFocusOnMatch,
SetAttention, SetInputFocus],
UserTerminal USING [Background, hasBorder, screenHeight,
screenWidth, SetBackground, SetBorder],
Window USING [Box, GetBox, GetParent, Handle];
Kaleidoscope: MONITOR
IMPORTS
Display, Exec, Heap, Inline, Process, Profile, MSegment,
ToolWindow, UserInput, UserTerminal, Window =
BEGIN
Bit: TYPE = MACHINE DEPENDENT {on(0), off(1)};
BitDesc: TYPE = MACHINE DEPENDENT RECORD
[offset(0: 0..7): [0..377B] ← 0,
pos(0: 8..11): [0..17B] ← 0,
size(0: 12..15): [0..17B] ← 1];
z: UNCOUNTED ZONE ← Heap.Create[2];
Generator: TYPE = RECORD[a, b, c: INTEGER, periodCount: CARDINAL];
period: CARDINAL;
persistence: CARDINAL;
windowSide: CARDINAL ← 256;
screenWidthWords: CARDINAL = EVEN[(windowSide+15)/16];
screenAreaWords: CARDINAL = screenWidthWords*windowSide;
screenAreaPages: CARDINAL =
(screenAreaWords+Environment.wordsPerPage-1)/Environment.wordsPerPage;
spotShift: INTEGER = -(Environment.bitsPerWord - Log2[windowSide/2]);
boxEdge: INTEGER = windowSide + 2;
toolBox: Window.Box ← [[50, 50], [boxEdge, boxEdge]];
bigBox: Window.Box ← [[0, 0], [4*windowSide+2, 3*windowSide+2]];
xStateB: Generator ← [1, -1849,3,];
xStateE: Generator ← TRASH;
yStateB: Generator ← [1, -1809,3,];
yStateE: Generator ← TRASH;
pBitmap: LONG POINTER TO UNSPECIFIED ← NIL;
bitmapSeg: MSegment.Handle ← NIL;
toolWindow, subWindow: Window.Handle ← NIL;
wait: CONDITION ← [timeout: Process.SecondsToTicks[1]];
finished: CONDITION;
bouncer: PROCESS;
running: BOOLEAN ← FALSE;
stop: BOOLEAN ← FALSE;
MakeDesc: PROCEDURE [UNSPECIFIED] RETURNS [BitDesc] =
MACHINE CODE {Mopcodes.zLI4; Mopcodes.zSHIFT};
Log2: PROCEDURE [n: CARDINAL] RETURNS [log: INTEGER] =
BEGIN
log ← SELECT n FROM
>= 100000B => 15,
>= 40000B => 14,
>= 20000B => 13,
>= 10000B => 12,
>= 4000B => 11,
>= 2000B => 10,
>= 1000B => 9,
>= 400B => 8,
>= 200B => 7,
>= 100B => 6,
>= 40B => 5,
>= 20B => 4,
>= 10B => 3,
>= 4 => 2,
>= 2 => 1,
ENDCASE => 0;
END;
Set: PROCEDURE [value: Bit, word: LONG POINTER, desc: BitDesc] =
MACHINE CODE {Mopcodes.zWLFS};
EVEN: PROCEDURE [v: UNSPECIFIED] RETURNS [UNSPECIFIED] =
INLINE {RETURN[v+Inline.BITAND[v, 1]]};
Advance: ENTRY PROCEDURE [state: LONG POINTER TO Generator] =
BEGIN OPEN state;
a ← Inline.BITXOR[(a+b), b];
periodCount ← periodCount - 1;
IF periodCount = 0 THEN {b ← Inline.BITXOR[(b+c), c]; periodCount ← period};
END;
Spots: PROCEDURE [x, y: INTEGER] =
BEGIN -- Draw 8 spots with kaleidoscopic symmetry
x0: CARDINAL = Inline.BITSHIFT[x, spotShift];
y0: CARDINAL = Inline.BITSHIFT[y, spotShift];
IF x0 < y0 THEN -- Discard points in other triangle
BEGIN
x1: CARDINAL = (windowSide-1)-x0;
y1: CARDINAL = (windowSide-1)-y0;
Set[on, pBitmap+x0*screenWidthWords, MakeDesc[y0]];
Set[on, pBitmap+y0*screenWidthWords, MakeDesc[x0]];
Set[on, pBitmap+x1*screenWidthWords, MakeDesc[y0]];
Set[on, pBitmap+y0*screenWidthWords, MakeDesc[x1]];
Set[on, pBitmap+x1*screenWidthWords, MakeDesc[y1]];
Set[on, pBitmap+y1*screenWidthWords, MakeDesc[x1]];
Set[on, pBitmap+x0*screenWidthWords, MakeDesc[y1]];
Set[on, pBitmap+y1*screenWidthWords, MakeDesc[x0]];
END;
END;
Erases: PROCEDURE [x, y: INTEGER] =
BEGIN -- Same as Spots except this erases.
x0: CARDINAL = Inline.BITSHIFT[x, spotShift];
y0: CARDINAL = Inline.BITSHIFT[y, spotShift];
IF x0 < y0 THEN
BEGIN
x1: CARDINAL = (windowSide-1)-x0;
y1: CARDINAL = (windowSide-1)-y0;
Set[off, pBitmap+x0*screenWidthWords, MakeDesc[y0]];
Set[off, pBitmap+y0*screenWidthWords, MakeDesc[x0]];
Set[off, pBitmap+x1*screenWidthWords, MakeDesc[y0]];
Set[off, pBitmap+y0*screenWidthWords, MakeDesc[x1]];
Set[off, pBitmap+x1*screenWidthWords, MakeDesc[y1]];
Set[off, pBitmap+y1*screenWidthWords, MakeDesc[x1]];
Set[off, pBitmap+x0*screenWidthWords, MakeDesc[y1]];
Set[off, pBitmap+y1*screenWidthWords, MakeDesc[x0]];
END;
END;
PaintKals: ENTRY PROCEDURE = {
FOR i: CARDINAL IN [0..4) DO
FOR j: CARDINAL IN [0..3) DO
Display.Bitmap[
window: subWindow,
box: [[i*windowSide, j*windowSide], [windowSide, windowSide]],
address: [pBitmap,0,0], bitmapBitWidth: windowSide,
flags: Display.replaceFlags];
ENDLOOP;
ENDLOOP;
};
NotifyQuit: ENTRY PROC = {NOTIFY finished};
Run: PROCEDURE =
BEGIN
ENABLE UNWIND => NULL;
oldBackground: UserTerminal.Background ← UserTerminal.SetBackground[white];
IF UserTerminal.hasBorder THEN UserTerminal.SetBorder[377B, 377B];
Process.SetPriority[Process.priorityBackground];
running ← TRUE;
xStateB.periodCount ← period;
yStateB.periodCount ← period;
xStateE ← xStateB;
yStateE ← yStateB;
FOR i: CARDINAL IN[1..persistence] DO -- Run the b(egin) generators ahead
[] ← Advance[@xStateB];
[] ← Advance[@yStateB];
[] ← Spots[xStateB.a, yStateB.a];
ENDLOOP;
DO -- Main loop
ENABLE ABORTED => EXIT;
THROUGH [0..16) DO
Advance[@xStateE]; Advance[@yStateE]; -- Advance and erase 8 spots
Erases[xStateE.a, yStateE.a];
Advance[@xStateB]; Advance[@yStateB]; -- Advance and put 8 spots
Spots[xStateB.a, yStateB.a];
ENDLOOP;
PaintKals[];
Process.Yield[];
IF stop THEN {NotifyQuit[]; EXIT};
ENDLOOP;
running ← FALSE;
[] ← UserTerminal.SetBackground[oldBackground];
IF UserTerminal.hasBorder THEN UserTerminal.SetBorder[210B, 42B];
END;
MyDisplay: PROC[Window.Handle] = {
Display.Black[subWindow, [[0,0], subWindow.GetBox[].dims]];
PaintKals[];
};
AttentionProc: UserInput.AttentionProcType = {
Process.Detach[FORK StopRunning[toolWindow]]};
StopRunning: ENTRY PROCEDURE [w: Window.Handle] = {
Process.SetPriority[Process.priorityNormal];
stop ← TRUE;
WAIT finished;
[] ← ToolWindow.Deactivate[w]};
StartRunning: ENTRY PROC [window: Window.Handle] = {
IF running THEN RETURN;
IF subWindow = NIL THEN subWindow ← ToolWindow.CreateSubwindow[
parent: window, display: MyDisplay,
box: [[0,0], toolWindow.GetBox[].dims]];
UserInput.SetInputFocus[subWindow, NIL, FALSE];
UserInput.SetAttention[subWindow.GetParent[], AttentionProc];
UserInput.SetAttention[subWindow, AttentionProc];
pBitmap↑ ← 177777B;
Inline.LongCOPY[
from: pBitmap, to: pBitmap+1,
nwords: screenAreaPages*256 - 1];
stop ← FALSE;
bouncer ← FORK Run;
running ← TRUE};
WaitTilFinished: ENTRY PROC = {WAIT finished};
TransitionProc: ToolWindow.TransitionProcType = {
ENABLE UNWIND => NULL;
SELECT new FROM
inactive, tiny => {
IF old = active THEN {
UserInput.ClearInputFocusOnMatch[subWindow];
IF ~stop THEN {stop ← TRUE; WaitTilFinished[]};
Process.Abort[bouncer];
JOIN bouncer};
IF new = inactive THEN subWindow ← NIL};
active => IF old # active THEN StartRunning[window];
ENDCASE};
KalCommand: Exec.ExecProc = {ToolWindow.Activate[toolWindow]};
AdjustProc: ENTRY ToolWindow.AdjustProcType = {};
Init: PROCEDURE =
BEGIN
i,j: CARDINAL ← 0;
period ← 10000;
persistence ← 5000;
bitmapSeg ← MSegment.Create[file: NIL, release: [],
fileBase: 0, pages: screenAreaPages];
pBitmap ← MSegment.Address[bitmapSeg];
toolWindow ← ToolWindow.Create[
name: "Kaleidoscope"L, adjust: AdjustProc, transition: TransitionProc,
box: [place: [0,0],
dims: [w: UserTerminal.screenWidth, h: UserTerminal.screenHeight]],
initialState: Profile.initialToolStateDefault, named: FALSE];
IF Profile.initialToolStateDefault # inactive THEN {
TransitionProc[
window: toolWindow, old: inactive, new: Profile.initialToolStateDefault];
ToolWindow.Show[toolWindow]};
Exec.AddCommand["Kaleidoscope.~"L, KalCommand];
Process.EnableAborts[@wait];
Process.DisableTimeout[@finished];
END;
Init[];
END...