-- screen rectangle monitor of chipmonk -- last modified by McCreight, January 10, 1983 12:57 PM -- to clean up aborts DIRECTORY ProcessDefs, InlineDefs, multiGraphicsDefs, ppdddefs, ppddefs, ppdefs; pprect: MONITOR IMPORTS ppdefs, ppddefs, ppdddefs, ProcessDefs EXPORTS ppdefs = BEGIN OPEN ProcessDefs, multiGraphicsDefs, InlineDefs, ppdefs, ppddefs, ppdddefs; maxCA: CARDINAL = 30; ctable: TYPE = RECORD [ fCnt: CARDINAL, -- number of pending repaint commands idx: CARDINAL, -- tail of repaint command queue nidx: CARDINAL, -- head of repaint command queue a: ARRAY [0..maxCA) OF sCmd, abrt: PROC ]; colTab, bwTab: ctable; initRects: PUBLIC ENTRY PROC = BEGIN colTab.fCnt ← bwTab.fCnt ← 0; colTab.idx ← bwTab.idx ← 0; colTab.abrt ← StopColCleanly; bwTab.abrt ← StopBWCleanly; END; CenterAndScale: PUBLIC ENTRY PROC [center: Point, scale: INTEGER, bw, col: BOOLEAN ← FALSE] = BEGIN scaleArray: ARRAY [1..20] OF RECORD [INTEGER, INTEGER] ← [ [1,256],[1,128],[1, 64],[1, 32], [1, 16], [1, 8], [1, 4], [1, 2], [1, 1], [2,1],[3,1],[4, 1], [6, 1], [8, 1], [12, 1], [16, 1], [24, 1],[32,1],[ 48, 1], [64, 1]]; IF bw THEN BEGIN StopBWCleanly[]; -- about to make major changes in global variables bwScale ← scale; [bwScaleN, bwScaleD] ← scaleArray[scale]; gridBW ← bwScaleN*lambdaGrid; bwxoff ← (300*bwScaleD)/bwScaleN - center.x; bwyoff ← ((bwBottom/2)*bwScaleD)/bwScaleN - center.y; bwxoff ← bwxoff - (bwxoff MOD lambdaGrid); bwyoff ← bwyoff - (bwyoff MOD lambdaGrid); bwClipx2 ← (606*bwScaleD)/bwScaleN - bwxoff; bwClipy2 ← (bwBottom*bwScaleD)/bwScaleN - bwyoff; bwClipx1 ← -bwxoff; bwClipy1 ← -bwyoff; reDrawRectInternal[r: [0,0,0,0], whenErase: 1, bw: TRUE, col: FALSE, all: TRUE]; END; IF col THEN BEGIN StopColCleanly[]; cScale ← scale; [cScaleN, cScaleD] ← scaleArray[scale]; gridCol ← cScaleN*lambdaGrid; cxoff ← ((colWidth/2)*cScaleD)/cScaleN - center.x; cyoff ← ((colHeight/2)*cScaleD)/cScaleN - center.y; cxoff ← cxoff - (cxoff MOD lambdaGrid); cyoff ← cyoff - (cyoff MOD lambdaGrid); cClipx2 ← (colWidth*cScaleD)/cScaleN - cxoff; cClipy2 ← (colHeight*cScaleD)/cScaleN - cyoff; cClipx1 ← -cxoff; cClipy1 ← -cyoff; reDrawRectInternal[r: [0,0,0,0], whenErase: 1, bw: FALSE, col: TRUE, all: TRUE]; END; END; reDrawRect: PUBLIC ENTRY PROC [ r: Rect, whenErase: CARDINAL, bw, col, all: BOOLEAN] = {reDrawRectInternal[r, whenErase, bw, col, all]}; reDrawRectInternal: INTERNAL PROC [ r: Rect, whenErase: CARDINAL, bw, col, all: BOOLEAN] = BEGIN -- note must be called with x1<=x2, y1<=y2 cmd: sCmd; a, b, c, d: INTEGER; bb: BOOLEAN; cmd.cmd ← IF all THEN all ELSE rect; cmd.p ← NIL; cmd.ers ← whenErase # 0; IF bw THEN BEGIN IF all THEN BEGIN cmd.r.x1 ← bwClipx1; cmd.r.x2 ← bwClipx2; cmd.r.y1 ← bwClipy1; cmd.r.y2 ← bwClipy2; a ← b ← 0; c ← d ← 1200; END ELSE BEGIN [bb, a, b, c, d] ← bwscaleRect[r.x1, r.y1, r.x2, r.y2]; IF bb THEN BEGIN cmd.r.x1 ← MAX[bwClipx1, r.x1]; cmd.r.x2 ← MIN[bwClipx2, r.x2]; cmd.r.y1 ← MAX[bwClipy1, r.y1]; cmd.r.y2 ← MIN[bwClipy2, r.y2]; END ELSE bw ← FALSE; END; END; IF bw THEN {insRect[cmd, @bwTab]; BROADCAST bwAvail}; IF col THEN BEGIN IF all THEN BEGIN cmd.r.x1 ← cClipx1; cmd.r.x2 ← cClipx2; cmd.r.y1 ← cClipy1; cmd.r.y2 ← cClipy2; a ← b ← 0; c ← d ← 1200; END ELSE BEGIN [bb, a, b, c, d] ← cscaleRect[r.x1, r.y1, r.x2, r.y2]; IF bb THEN BEGIN cmd.r.x1 ← MAX[cClipx1, r.x1]; cmd.r.x2 ← MIN[cClipx2, r.x2]; cmd.r.y1 ← MAX[cClipy1, r.y1]; cmd.r.y2 ← MIN[cClipy2, r.y2]; END ELSE col ← FALSE; END; END; IF col THEN {insRect[cmd, @colTab]; BROADCAST colAvail}; END; drawNewlySel: PUBLIC ENTRY PROC [p: LONG POINTER TO list] = BEGIN cmd: sCmd; cmd.cmd ← sel; cmd.p ← p; cmd.ers ← TRUE; insRect[cmd, @bwTab]; BROADCAST bwAvail; insRect[cmd, @colTab]; BROADCAST colAvail; END; insRect: INTERNAL PROC [c: sCmd, t: POINTER TO ctable] = BEGIN inside: PROC [a, b: Rect] RETURNS [BOOLEAN] = -- True if a inside b {RETURN[NOT (a.x1 < b.x1 OR a.y1 < b.y1 OR a.x2 > b.x2 OR a.y2 > b.y2)]}; IF t.fCnt >= maxCA OR c.cmd=all THEN BEGIN -- replace with single command to repaint everything t.abrt[]; --abort the current queue t.idx ← t.nidx ← 0; t.a[0] ← c; t.a[0].cmd ← all; t.fCnt ← 1; RETURN; END; IF t.fCnt > 0 AND t.a[t.idx].cmd = all THEN RETURN; -- we're going to repaint everything anyway IF c.cmd = rect THEN BEGIN i: CARDINAL ← t.nidx; THROUGH [0..t.fCnt) DO -- see if our repaint can include or be included in a previous one IF t.a[i].cmd = rect THEN BEGIN IF inside[c.r, t.a[i].r] THEN {t.a[i].ers ← t.a[i].ers OR c.ers; RETURN}; IF inside[t.a[i].r, c.r] THEN {t.a[i].ers ← t.a[i].ers OR c.ers; t.a[i].r ← c.r; RETURN}; END; i ← Inc[i]; ENDLOOP; END; -- add the new command to the queue t.idx ← IF t.fCnt = 0 THEN (t.nidx ← 0) ELSE Inc[t.idx]; t.a[t.idx] ← c; t.fCnt ← t.fCnt + 1; END; Inc: PROC [i: CARDINAL] RETURNS [CARDINAL] = INLINE BEGIN RETURN[IF i >= maxCA - 1 THEN 0 ELSE i + 1]; END; colAvail, bwAvail, colPainterAck, bwPainterAck: CONDITION; StopColCleanly: INTERNAL PROC [] = BEGIN abortColor ← TRUE; colTab.fCnt ← 0; WHILE abortColor DO NOTIFY colAvail; WAIT colPainterAck; ENDLOOP; END; getColNewRect: PUBLIC ENTRY PROC RETURNS [sCmd] = BEGIN i: CARDINAL; WHILE colTab.fCnt = 0 DO WAIT colAvail; abortColor ← FALSE; NOTIFY colPainterAck; ENDLOOP; i ← colTab.nidx; colTab.nidx ← Inc[i]; colTab.fCnt ← colTab.fCnt - 1; RETURN[colTab.a[i]]; END; StopBWCleanly: INTERNAL PROC [] = BEGIN abortBW ← TRUE; bwTab.fCnt ← 0; WHILE abortBW DO NOTIFY bwAvail; WAIT bwPainterAck; ENDLOOP; END; getBwNewRect: PUBLIC ENTRY PROC RETURNS [sCmd] = BEGIN i: CARDINAL; WHILE bwTab.fCnt = 0 DO WAIT bwAvail; abortBW ← FALSE; NOTIFY bwPainterAck; ENDLOOP; i ← bwTab.nidx; bwTab.nidx ← Inc[i]; bwTab.fCnt ← bwTab.fCnt - 1; RETURN[bwTab.a[i]]; END; InitializeCondition[condition: @colAvail, ticks: MsecToTicks[200]]; InitializeCondition[condition: @bwAvail, ticks: MsecToTicks[200]]; InitializeCondition[condition: @colPainterAck, ticks: MsecToTicks[200]]; InitializeCondition[condition: @bwPainterAck, ticks: MsecToTicks[200]]; initRects[]; END.