LutherWatcherSpecialCache.mesa
Russ Atkinson, January 6, 1984 6:50 pm
Special accelerator cache for BugBane only!
DIRECTORY
BasicTime,
FastBreak,
Graphics USING
[black, Context, DrawBox, NewContext, SetColor, SetCP, SetPaintMode, white],
GraphicsOps USING
[BitmapRef, BitmapRep, Context, DrawBitmap, NewBitmap, NewContextFromBitmap],
Icons USING [DrawIcon],
PrincOps USING
[BytePC, ControlLink, CSegPrefix, GlobalFrameHandle, NullLink, StateVector],
PrincOpsUtils USING [GetReturnLink, GlobalFrame],
Process USING [GetPriority, Priority, priorityClient3, SetPriority],
Rope USING [ROPE],
Terminal USING [Current, WaitForBWVerticalRetrace],
ViewerClasses USING [Viewer],
ViewerOps USING
[DisablePainting, EnablePainting, FindViewer, GreyScreen, OpenIcon, PaintViewer, WaitForPaintingToFinish];
LutherWatcherSpecialCache: MONITOR -- Russ's SpecialCache, cloned.
IMPORTS
BasicTime, FastBreak, Graphics, GraphicsOps, Icons, PrincOpsUtils, Process, Terminal, ViewerOps
SHARES ViewerOps
= BEGIN OPEN Rope;
MapSeq: TYPE = RECORD
[SEQUENCE len: NAT OF Map];
Map: TYPE = RECORD [
x0, y0: CARDINAL ← 0,
xpos,ypos: INTEGER ← 0,
xvel,yvel: INTEGER ← 0];
CARD: TYPE = LONG CARDINAL;
base: GraphicsOps.BitmapRef ← NIL;
blinks: INTEGER ← 4;
ctx: Graphics.Context ← NIL;
enabled: BOOLTRUE;
hack: REF GraphicsOps.BitmapRep ← NIL;
iconCtx: Graphics.Context ← NIL;
iconSize: INTEGER = 64;
invG: INTEGER ← 2; -- number of steps between gravity increment
lockup: BOOLTRUE; -- TRUE for production, FALSE for debug
maps: REF MapSeq ← NEW[MapSeq[64]];
maxTime: INT ← 32; -- don't hog the world for more than about this many seconds
minYvel: INTEGER ← 3;
pieces: BOOLTRUE;
pieceSize: NAT ← 24;
scale: INTEGER ← 1;
scanLines: INTEGER ← 0;
seedMod: INTEGER ← 64;
swapPiecesFlag: BOOLFALSE;
setList: LocalData ← NIL;
initialSteps: INTEGER = 80;
bouncingBottom: BOOLTRUE;
bouncingTop: BOOLTRUE;
bouncingSides: BOOLTRUE;
absorbing: NAT ← 7;
LocalData: TYPE = REF LocalDataRep;
LocalDataRep: TYPE = RECORD [
next: LocalData ← NIL,
id: FastBreak.FastBreakId ← NIL,
viewer: ViewerClasses.Viewer ← NIL,
oneShot: BOOLTRUE];
FrameType: TYPE = RECORD
[w0,w1,w2,w3: CARDINAL, viewer: ViewerClasses.Viewer];
HandleCacheChange: FastBreak.FastBreakProc = TRUSTED {
[data: FastBreakData, frame: PrincOps.FrameHandle, sv: PrincOps.SVPointer]
RETURNS [useOldBreak: BOOL ← FALSE]
mine: LocalData ← LOOPHOLE[data];
ptr: POINTER TO FrameType ← LOOPHOLE[frame];
current: BasicTime.Pulses ← BasicTime.GetClockPulses[];
viewer: ViewerClasses.Viewer ← ptr.viewer;
IF viewer = NIL OR NOT viewer.iconic THEN RETURN;
IF mine # NIL AND enabled AND
mine.id # NIL AND (mine.viewer = NIL OR viewer = mine.viewer) THEN {
IF mine.oneShot THEN {
[] ← FastBreak.ClearFastBreak[mine.id, HandleCacheChange, data];
mine.id ← NIL;
};
DoIt[viewer];
};
};
ProcToCodeAndPC: PROC
[proc: UNSPECIFIED] RETURNS [code: LONG POINTERNIL, pc: PrincOps.BytePC] = {
gfh: PrincOps.GlobalFrameHandle ← LOOPHOLE[PrincOpsUtils.GlobalFrame[proc]];
pc ← [0];
IF gfh # NIL THEN {
ep: CARDINALLOOPHOLE[proc, PrincOps.ControlLink].ep;
ev: LONG POINTER TO PrincOps.CSegPrefix ← LOOPHOLE[gfh.code.longbase];
pc ← [ev.entry[ep].initialpc*2];
code ← ev;
};
};
FindAny: PROC [oneShot: BOOLFALSE] = {
ENABLE ANY => GO TO dont;
proc: UNSPECIFIED ← ViewerOps.OpenIcon;
code: LONG POINTER;
pc: PrincOps.BytePC;
data: LocalData ← NIL;
Setup[];
[code, pc] ← ProcToCodeAndPC[proc];
pc ← [pc+5]; -- crock! to get at frame after arguments
data ← NEW[LocalDataRep ← [
next: NIL, id: NIL, viewer: NIL,
oneShot: oneShot]];
data.id ← FastBreak.SetFastBreak[code, pc, HandleCacheChange, LOOPHOLE[data]];
data.next ← setList;
setList ← data;
EXITS
dont => {};
};
FindIt: PROC [name: ROPE, oneShot: BOOLFALSE] = {
ENABLE ANY => GO TO dont;
viewer: ViewerClasses.Viewer ← ViewerOps.FindViewer[name];
proc: UNSPECIFIED ← ViewerOps.OpenIcon;
code: LONG POINTER;
pc: PrincOps.BytePC;
data: LocalData ← NIL;
Setup[];
IF viewer = NIL OR NOT viewer.iconic THEN RETURN;
[code, pc] ← ProcToCodeAndPC[proc];
pc ← [pc+5]; -- crock! to get at frame after arguments
data ← NEW[LocalDataRep ← [
next: NIL, id: NIL, viewer: viewer,
oneShot: oneShot]];
data.id ← FastBreak.SetFastBreak[code, pc, HandleCacheChange, LOOPHOLE[data]];
data.next ← setList;
setList ← data;
EXITS
dont => {};
};
NameIt: PROC [name: ROPE] = {
viewer: ViewerClasses.Viewer ← ViewerOps.FindViewer[name];
IF viewer = NIL OR NOT viewer.iconic THEN RETURN;
DoIt[viewer];
ViewerOps.PaintViewer[viewer, all];
};
DoIt: PROC [viewer: ViewerClasses.Viewer] = {
x: INTEGER ← viewer.wx;
midWay: INTEGER ← Terminal.Current[].bwWidth/2;
vx: INTEGER ← (midWay - x)/initialSteps;
y: INTEGER ← viewer.wy;
oldPriority: Process.Priority ← Process.GetPriority[];
nextG: INTEGER ← invG;
useIcon: BOOL ← viewer.icon < private;
startTime: BasicTime.GMT ← BasicTime.Now[];
last: BOOLFALSE;
maxX: INTEGER = Terminal.Current[].bwWidth - (IF pieces THEN pieceSize ELSE iconSize);
minY: INTEGER = IF pieces THEN pieceSize/2 ELSE iconSize/2;
maxY: INTEGER = Terminal.Current[].bwHeight;
lastTime: INT ← maxTime;
needErase: BOOLFALSE;
IF NOT viewer.iconic THEN RETURN;
load the bitmaps with the patterns
Setup[];
IF useIcon
THEN Icons.DrawIcon[viewer.icon, iconCtx, 0, 0, viewer.name]
ELSE viewer.class.paint[viewer, iconCtx, NIL, FALSE];
Process.SetPriority[Process.priorityClient3];
ViewerOps.WaitForPaintingToFinish[];
ViewerOps.GreyScreen[x, y, iconSize, iconSize, FALSE, TRUE]; -- wipe out the old icon
IF lockup THEN {
ViewerOps.DisablePainting[];
ViewerOps.WaitForPaintingToFinish[]};
move icon to the center
SELECT vx FROM
< 0 => vx ← vx - 1;
> 0 => vx ← vx + 1;
ENDCASE;
DO
oldX: INTEGER ← x;
oldY: INTEGER ← y;
last: BOOLFALSE;
step the position
x ← x + vx;
y ← y + 2;
SELECT vx FROM
> 0 => IF x > midWay THEN x ← midWay;
< 0 => IF x < midWay THEN x ← midWay;
ENDCASE;
IF x = midWay OR y > 500
THEN last ← TRUE
ELSE {
XOR in the new image
Graphics.SetCP[ctx, x, y+iconSize];
GraphicsOps.DrawBitmap[ctx, base, iconSize, iconSize, 0, 0];
};
IF needErase THEN {
XOR out the original image
Graphics.SetCP[ctx, oldX, oldY+iconSize];
GraphicsOps.DrawBitmap[ctx, base, iconSize, iconSize, 0, 0];
};
needErase ← TRUE;
Terminal.WaitForBWVerticalRetrace[Terminal.Current[]];
IF last THEN EXIT;
ENDLOOP;
init the maps to point at the icon and to have the correct positions
FOR i: NAT IN [0..maps.len) DO
map: Map ← maps[i];
map.xpos ← map.xpos + x;
map.ypos ← map.ypos + y + iconSize;
maps[i] ← map;
ENDLOOP;
explode the icon in steps
FOR i: NAT IN [0..4800) WHILE NOT last DO
current: BasicTime.GMT ← BasicTime.Now[];
delta: INT ← BasicTime.Period[from: startTime, to: current];
moving: NAT ← maps.len;
above: NAT ← moving;
last ← delta > lastTime;
loop each bitmap
FOR j: NAT IN [0..moving) DO
map: Map ← maps[j];
oldX: INTEGER ← map.xpos;
oldY: INTEGER ← map.ypos;
step the position
IF nextG = i THEN
apply a gravity step
map.yvel ← map.yvel - 1;
map.xpos ← oldX + map.xvel;
map.ypos ← oldY + map.yvel;
IF bouncingSides THEN
SELECT map.xpos FROM
<= 0 => {map.xvel ← -(map.xvel*3)/absorbing; map.xpos ← 0};
>= maxX => {map.xvel ← -(map.xvel*3)/absorbing; map.xpos ← maxX};
ENDCASE;
IF bouncingBottom THEN
IF map.ypos <= minY THEN {
map.yvel ← -(map.yvel*3)/absorbing;
map.ypos ← minY;
IF map.yvel = 0 AND map.ypos = minY AND (i MOD 16) = 0 THEN
friction, of a sort
SELECT map.xvel FROM
< 0 => map.xvel ← map.xvel + 1;
> 0 => map.xvel ← map.xvel - 1;
ENDCASE;
IF map.yvel = 0 AND map.xvel = 0 THEN moving ← moving - 1;
};
IF bouncingTop THEN
IF map.ypos >= maxY THEN {
map.yvel ← -(map.yvel*3)/absorbing;
map.ypos ← maxY};
IF map.ypos < minY THEN above ← above - 1;
maps[j] ← map;
XOR in the new image
IF NOT last THEN {
Graphics.SetCP[ctx, map.xpos, map.ypos];
IF pieces
THEN GraphicsOps.DrawBitmap[
ctx, base, pieceSize, pieceSize, map.x0, map.y0, map.x0, map.y0]
ELSE GraphicsOps.DrawBitmap[ctx, base, iconSize, iconSize, 0, 0]};
IF i # 0 THEN {
XOR out the original image
Graphics.SetCP[ctx, oldX, oldY];
IF pieces
THEN GraphicsOps.DrawBitmap[
ctx, base, pieceSize, pieceSize, map.x0, map.y0, map.x0, map.y0]
ELSE GraphicsOps.DrawBitmap[ctx, base, iconSize, iconSize, 0, 0]};
ENDLOOP;
IF nextG = i THEN nextG ← nextG + invG;
THROUGH [0..scanLines) DO
Terminal.WaitForBWVerticalRetrace[Terminal.Current[]];
ENDLOOP;
IF moving = 0 OR above = 0 THEN lastTime ← 0;
ENDLOOP;
cleanup
IF swapPiecesFlag THEN pieces ← NOT pieces;
IF lockup THEN ViewerOps.EnablePainting[];
Process.SetPriority[oldPriority];
ViewerOps.WaitForPaintingToFinish[];
};
FlushCache: PROC = {
takes any # of arguments and flushes them
v: RECORD [a,b: UNSPECIFIED, state: PrincOps.StateVector];
v.state ← STATE;
v.state.dest ← PrincOpsUtils.GetReturnLink[];
v.state.source ← PrincOps.NullLink;
v.state.stkptr ← 0;
RETURN WITH v.state;
};
Setup: ENTRY PROC = {
ENABLE UNWIND => NULL;
IF ctx = NIL THEN {
ctx ← Graphics.NewContext[];
Graphics.SetColor[ctx, Graphics.black];
[] ← Graphics.SetPaintMode[ctx, invert]};
IF base = NIL THEN {
base ← GraphicsOps.NewBitmap[iconSize, iconSize];
hack ← LOOPHOLE[base]};
iconCtx ← GraphicsOps.NewContextFromBitmap[base];
[] ← Graphics.SetPaintMode[iconCtx, opaque];
Graphics.SetColor[iconCtx, Graphics.white];
Graphics.DrawBox[iconCtx, [0, 0, 64, 64]];
Graphics.SetColor[iconCtx, Graphics.black];
FOR i: NAT IN [0..maps.len) DO
row: INTEGER ← i / 8;
col: INTEGER ← i MOD 8;
sum: INTEGER ← row + col;
xvel: INTEGER ← (seedMod/2 - GenRandom[]) * scale;
yvel: INTEGER ← (GenRandom[] + minYvel) * scale;
x0: INTEGER ← col * 8;
y0: INTEGER ← row * 8;
maps[i] ← [x0: x0, y0: y0, xpos: x0, ypos: y0, xvel: xvel, yvel: yvel];
ENDLOOP;
};
seed: CARDINAL ← 123456B;
GenRandom: PROC RETURNS [INTEGER] = {
returns pseudo-random number in [0..seedMod)
seed ← seed * 17 + 174653B;
RETURN [(seed / 256) MOD seedMod];
};
END.