Magnifier.mesa; Written by S. McGregor
Last Edited by: McGregor, July 18, 1983 9:17 am
Last Edited by: Beach, October 4, 1983 3:38 pm
DIRECTORY
BitBlt USING [AlignedBBTable, BITBLT, BBptr, BBTableSpace],
Buttons,
Cursors USING [SetCursor],
CGScreen USING [Bits],
Environment USING [BitAddress],
InputFocus,
Mopcodes,
Process,
TIPUser,
UserTerminal,
ViewerLocks USING [LockViewerTree, ReleaseViewerTree],
ViewerClasses,
ViewerSpecs USING [screenH, screenW];

Magnifier: PROGRAM
IMPORTS BitBlt, Buttons, Cursors, CGScreen, InputFocus, Process, TIPUser, UserTerminal, ViewerLocks
SHARES ViewerLocks = BEGIN OPEN Mopcodes;
pMask: REF; -- pointer to mask bits  (0 => opaque, 1 => transparent)
pImage: REF; -- pointer to image bits  (0 => white, 1 => black)
pSaved: REF; -- pointer to screen bits (0 => white, 1 => black)
pRaster: CARDINAL; -- words per line
pWidth: CARDINAL; -- width in bits
pHeight: CARDINAL; -- height in lines
pX, pY: INTEGER; -- last position
lock: BOOL; -- viewer paints locked out
magnify: BOOLFALSE;
magX, magY, magW, magH: CARDINAL;
AllocateBitmap: PROC [nWords: CARDINAL] RETURNS [REF] = INLINE BEGIN
Words: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF CARDINAL];
RETURN[NEW[Words[nWords]]];
END;
MagnifyRegion: PROC [leftX, topY, widthInWords, height: CARDINAL] = BEGIN
magnify ← TRUE;
magX ← leftX;
magY ← topY;
magW ← widthInWords;
magH ← height;
END;
NewPicture: PROC [mask: REF, image: REF, raster, width, height, screenX, screenY: CARDINAL, lockPainting: BOOLTRUE] = BEGIN
pMask ← mask;
pImage ← image;
pSaved ← AllocateBitmap[raster*height];
pRaster ← raster;
pWidth ← width;
pHeight ← height;
pX ← MIN[screenX, ViewerSpecs.screenW-width];
screenY ← ViewerSpecs.screenH-screenY; -- invert conversion
pY ← MIN[screenY, ViewerSpecs.screenH-height];
lock ← lockPainting;
ComputeScreenPoint[];
sfsp.dst ← [LOOPHOLE[pSaved],,0];
sfsp.dstBpl ← pRaster*16;
sfsp.width ← pWidth;
sfsp.height ← pHeight;
itsp.srcDesc.srcBpl ← pRaster*16;
itsp.width ← pWidth;
itsp.height ← pHeight;
Cursors.SetCursor[blank];
IF lock THEN ViewerLocks.LockViewerTree[];
BLTImageToScreen[];
END;
MovePicture: PROC [screenX, screenY: CARDINAL] = BEGIN
BLTSavedToScreen[];
pX ← MIN[screenX, ViewerSpecs.screenW-pWidth];
screenY ← ViewerSpecs.screenH-screenY; -- invert conversion
pY ← MIN[screenY, ViewerSpecs.screenH-pHeight];
ComputeScreenPoint[];
BLTImageToScreen[];
END;
TakeDownPicture: PROC = BEGIN
BLTSavedToScreen[];
IF lock THEN ViewerLocks.ReleaseViewerTree[];
Cursors.SetCursor[textPointer];
pMask ← pImage ← pSaved ← NIL;
magnify ← FALSE;
END;
ComputeScreenPoint: PROC = INLINE BEGIN
screenPoint.word ← screen + (LONG[pY]*(ViewerSpecs.screenW/16)) + (LONG[pX]/16);
screenPoint.bit ← pX MOD 16;
END;
screen: LONG POINTER ← CGScreen.Bits[].base;
screenPoint: Environment.BitAddress;
sfsTable, itsTable: BitBlt.BBTableSpace;
sfsp: BitBlt.BBptr ← BitBlt.AlignedBBTable[@sfsTable];
itsp: BitBlt.BBptr ← BitBlt.AlignedBBTable[@itsTable];
Pair: TYPE = ARRAY [0..1] OF CARDINAL;
PairPtr: TYPE = LONG POINTER TO Pair;
Get8: PROC [ptr: LONG POINTER, start: CARDINAL] RETURNS [word: CARDINAL] = INLINE {
dist: INTEGER = CardinalAnd[start,15];
pp: PairPtr = LOOPHOLE[ptr, PairPtr] + start / 16;
RETURN [
CardinalOr[
CardinalShiftLeft[pp[0], dist],
CardinalShiftLeft[pp[1], dist-16]]
/ 256];
};
Put16: PROC [ptr: LONG POINTER, start: CARDINAL, word: CARDINAL] = INLINE {
dist: INTEGER = CardinalAnd[start,15];
pp: PairPtr = LOOPHOLE[ptr, PairPtr] + start / 16;
pp[0] ← CardinalOr[
CardinalShiftRight[word, dist],
CardinalAnd[pp[0], CardinalShiftLeft[177777B, 16-dist]]];
pp[1] ← CardinalOr[
CardinalShiftLeft[word, 16-dist],
CardinalAnd[pp[1], CardinalShiftRight[177777B, dist]]];
};
CardinalShiftLeft: PROC
[word: CARDINAL, dist: INTEGER] RETURNS [CARDINAL] = MACHINE CODE {
Mopcodes.zSHIFT;
};
CardinalShiftRight: PROC
[word: CARDINAL, dist: INTEGER] RETURNS [CARDINAL] = MACHINE CODE {
Mopcodes.zNEG;
Mopcodes.zSHIFT;
};
CardinalOr: PROC [word1,word2: CARDINAL] RETURNS [CARDINAL] = MACHINE CODE {
Mopcodes.zOR;
};
CardinalAnd: PROC [word1,word2: CARDINAL] RETURNS [CARDINAL] = MACHINE CODE {
Mopcodes.zAND;
};
BLTImageToScreen: PROC = BEGIN
itsp.dst ← sfsp.src ← screenPoint;
BitBlt.BITBLT[sfsp]; -- save screen
IF magnify THEN BEGIN
screenAdd: LONG CARDINAL ← (magY+magH/4)*pRaster + magX/16;
imageAdd: LONG CARDINAL ← magY*pRaster + magX/16;
fetchOffset: CARDINAL = magX+magW*16/4;
screen: LONG POINTER = LOOPHOLE[pSaved];
image: LONG POINTER = LOOPHOLE[pImage];
THROUGH [0..magH/2) DO
FOR i: CARDINAL IN [0..magW) DO
word: CARDINAL = twoPower[Get8[screen+screenAdd, fetchOffset+(8*i)]];
xOff: CARDINAL = magX+(16*i);
Put16[image+imageAdd, xOff, word];
Put16[image+imageAdd+pRaster, xOff, word];
ENDLOOP;
screenAdd ← screenAdd + pRaster;
imageAdd ← imageAdd + (2*pRaster);
ENDLOOP;
END;
IF pMask#NIL THEN BEGIN
itsp.src ← [LOOPHOLE[pMask],,0];
itsp.flags.dstFunc ← and;
BitBlt.BITBLT[itsp];
itsp.flags.dstFunc ← or;
END;
itsp.src ← [LOOPHOLE[pImage],,0];
BitBlt.BITBLT[itsp];
itsp.flags.dstFunc ← null;
END;
BLTSavedToScreen: PROC = INLINE BEGIN
itsp.dst ← screenPoint;
itsp.src ← [LOOPHOLE[pSaved],,0];
BitBlt.BITBLT[itsp];
END;
twoPower: ARRAY [0..256) OF CARDINAL;
BuildTwoPower: PROC = BEGIN
scan: INTEGER;
p: POINTER TO PACKED ARRAY [0..8) OF BOOLLOOPHOLE[@scan];
p2: POINTER TO PACKED ARRAY [0..16) OF BOOLLOOPHOLE[@twoPower];
FOR i: INTEGER IN [0..256) DO
scan ← i;
FOR j: INTEGER IN [0..8) DO
p2[j*2] ← p[j];
p2[j*2+1] ← p[j];
ENDLOOP;
p2 ← p2+1;
ENDLOOP;
END;
magnifier: REF ARRAY [0..256) OF UNSPECIFIEDLOOPHOLE[AllocateBitmap[256]];
magnifier2: REF ARRAY [0..512) OF UNSPECIFIEDLOOPHOLE[AllocateBitmap[512]];
Start: Buttons.ButtonProc = TRUSTED BEGIN
InputFocus.SetInputFocus[];
InputFocus.CaptureButtons[Notify, myTIPTable];
IF mouseButton#red THEN BEGIN
MagnifyRegion[1, 1, 7, 62];
NewPicture[NIL, magnifier2, 8, 114, 64, 300, 300];
END
ELSE BEGIN
MagnifyRegion[1, 1, 3, 62];
NewPicture[NIL, magnifier, 4, 50, 64, 300, 300];
END;
Process.Detach[FORK DoIt[]];
END;
Notify: ViewerClasses.NotifyProc = TRUSTED {}; -- NOP
myTIPTable: TIPUser.TIPTable ← TIPUser.InstantiateNewTIPTable["Magnifier.tip"]; -- Known NOP
fudge: CARDINAL ← 150; -- fudge for retrace synch
DoIt: PROCEDURE = BEGIN
mouseBitsRec: TYPE = MACHINE DEPENDENT RECORD [ -- mouse buttons are inverted
fill: [0..8192), red: BOOL, blue: BOOL, yellow: BOOL];
mouseP: LONG POINTER TO mouseBitsRec = LOOPHOLE[UserTerminal.keyboard];
mouse: UserTerminal.Coordinate;
Process.SetPriority[3];
UNTIL ~mouseP.red DO
wait: CARDINAL;
UserTerminal.WaitForScanLine[
SELECT wait ← pY+fudge FROM
>808 => 0,
ENDCASE => wait];
IF UserTerminal.cursor^ # mouse THEN BEGIN
mouse ← UserTerminal.cursor^;
MovePicture[mouse.x, 808-mouse.y];
END;
ENDLOOP;
TakeDownPicture[];
InputFocus.ReleaseButtons[];
END;
sfsp.flags.disjoint ← TRUE;
sfsp.flags.disjointItems ← TRUE;
sfsp.srcDesc.srcBpl ← ViewerSpecs.screenW;
itsp.flags.disjoint ← TRUE;
itsp.flags.disjointItems ← TRUE;
itsp.dstBpl ← ViewerSpecs.screenW;
BuildTwoPower[];
magnifier[0] ← magnifier[1] ← magnifier[2] ← 177777B;
magnifier[252] ← magnifier[253] ← magnifier[254] ← 177777B;
magnifier[3] ← 140000B;
magnifier[255] ← 140000B;
FOR i: INTEGER IN [0..248/4) DO
magnifier[i*4+4] ← 100000B;
magnifier[i*4+7] ← 040000B;
ENDLOOP;
FOR i: INTEGER IN [0..6] DO
magnifier2[i] ← 177777B;
magnifier2[i+504] ← 177777B;
ENDLOOP;
magnifier2[7] ← magnifier2[511] ← 140000B;
FOR i: INTEGER IN [0..62) DO
magnifier2[i*8+8] ← 100000B;
magnifier2[i*8+15] ← 040000B;
ENDLOOP;
[] ← Buttons.Create[[name: "Magnifier"], Start];
END.