CKViewerOpsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last edited by Ken Pier, February 16, 1984 2:05:54 pm PST
Doug Wyatt, May 1, 1985 10:03:53 am PDT
Rick Beach, February 17, 1986 4:58:56 pm PST
DIRECTORY
PrincOps,
PrincOpsUtils,
Buttons,
ViewerOps,
CKViewerPanel,
CKViewerButtons,
MessageWindow,
Basics,
Real,
Process,
Terminal,
InterminalBackdoor;
CKViewerOpsImpl: CEDAR PROGRAM
IMPORTS PrincOpsUtils, Buttons, Terminal, InterminalBackdoor, Basics, Real, Process, MessageWindow, CKViewerButtons, ViewerOps
EXPORTS CKViewerButtons, CKViewerPanel
= BEGIN OPEN MW: MessageWindow;
CKViewer: TYPE = CKViewerButtons.CKViewer;
CKViewerState: TYPE = CKViewerButtons.CKViewerState;
terminal: Terminal.Virtual ~ InterminalBackdoor.terminal;
sym: BOOLEANFALSE;
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr;
grayword: CARDINAL ← 0;
bitmapB: Terminal.FrameBuffer ← NIL;
lbpp,lbppB: CARDINAL ← 0; -- log (base 2) bits per pixel
bpp,bppB: CARDINAL ← 0; -- bits per pixel
full: BOOLEANFALSE;
ashow,bshow: BOOLEANTRUE;
splat: BOOLEANTRUE;
cornerSize: CARDINAL ← 4;
cornerColor: CARDINAL ← 8;
Triple: TYPE = RECORD[r,g,b: [0..256)];
testmap: ARRAY[0..8] OF Triple ← [
[255,255,255], -- white
[255,255, 0], -- yellow
[ 0,255,255], -- cyan
[ 0,255, 0], -- green
[255, 0,255], -- magenta
[255, 0, 0], -- red
[ 0, 0,255], -- blue
[127,127,127], -- gray (background)
[ 0, 0, 0] -- black
];
black: [0..8] = 8; --testmap[8] is black
gray: [0..8] = 7; --testmap[8] is gray
white: [0..8] = 0; --testmap[0] is white
Diag: PROC [] = {
draw a set of diagonal lines
Bham: PROC [fx,fy,lx,ly: INTEGER, color: [0..8]] = {
draw a line from (fx,fy) to (lx,ly)
yt: REAL; xx, xi: INTEGER; yy, yi: INTEGER;
dx: INTEGER ← lx-fx;
dy: INTEGER ← ly-fy;
IF dy>dx OR dx<=0 OR dy<=0 THEN ERROR;
FOR xi IN [0..dx) DO
yt ← (Real.Float[dy]/Real.Float[dx])*Real.Float[xi];
yi ← Real.FixI[yt+0.5];
xx𡤏x+xi; yy𡤏y+yi;
TestRect[xx,yy,1,1,color];
TestRect[iWidth-xx,yy,1,1,color];
TestRect[xx,iHeight-yy,1,1,color];
TestRect[iWidth-xx,iHeight-yy,1,1,color];
ENDLOOP;
};
iWidth: INTEGER ← terminal.colorWidth;
iHeight: INTEGER ← terminal.colorHeight;
deltaX: INTEGER ← iWidth/40;
deltaY: INTEGER ← (deltaX*iHeight)/iWidth;
xi: INTEGER ← 0;
yi: INTEGER ← 0;
IF full THEN Positive[] ELSE {
FOR i: CARDINAL IN[0..9) DO
Terminal.SetColor[vt: terminal, aChannelValue: i, red: testmap[i].r, green: testmap[i].g, blue: testmap[i].b];
ENDLOOP;
SetShowButtons[TRUE,FALSE,FALSE];
};
TestRect[0,0,terminal.colorWidth,terminal.colorHeight,black]; --black background
FOR n: INTEGER ← 0, n+1 UNTIL xi >=iWidth DO
Bham[fx: xi, fy: 0, lx: iWidth-1, ly: iHeight-n*deltaY, color: white];
xi←xi+deltaX;
ENDLOOP;
};
ShowTPat: PROC = {
x: CARDINAL = 60;
h: CARDINAL = 60;
w: CARDINAL = 50;
gap: CARDINAL = 15;
IF full THEN Positive[] ELSE {
FOR i: CARDINAL IN[0..9) DO
Terminal.SetColor[vt: terminal, aChannelValue: i, red: testmap[i].r, green: testmap[i].g, blue: testmap[i].b];
ENDLOOP;
SetShowButtons[TRUE,FALSE,FALSE];
};
gray background
TestRect[0,0,terminal.colorWidth,terminal.colorHeight,gray];
four corners
{ s: CARDINAL = cornerSize;
c: CARDINAL = cornerColor; -- color
TestRect[0,0,s,s,c];
TestRect[terminal.colorWidth-s,0,s,s,c];
TestRect[0,terminal.colorHeight-s,s,s,c];
TestRect[terminal.colorWidth-s,terminal.colorHeight-s,s,s,c];
};
various colors at left edge
FOR i: CARDINAL IN[0..8) DO
r,g,b: [0..256);
r ← (i MOD 2)*255;
g ← ((i/2) MOD 2)*255;
b ← ((i/4) MOD 2)*255;
TestRect[4,i*h+10,x,h-20,i+1];
ENDLOOP;
a bunch of stripes
FOR i: CARDINAL IN[0..8) DO
r,g,b: [0..256);
r ← (i MOD 2)*255;
g ← ((i/2) MOD 2)*255;
b ← ((i/4) MOD 2)*255;
TestRect[x+i*w+gap,0,w-gap,8*h,i+1];
ENDLOOP;
};
TestRect: PROC[x,y,w,h: CARDINAL, i: [0..8]] = {
IF NOT (x<terminal.colorWidth AND y<terminal.colorHeight) THEN RETURN;
w ← MIN[w,terminal.colorWidth-x]; h ← MIN[h,terminal.colorHeight-y];
IF full THEN FullRect[x,y,w,h,testmap[i].r,testmap[i].g,testmap[i].b]
ELSE ARect[x,y,w,h,i];
};
Rect: PROC[x,y,w,h: CARDINAL, i: [0..256)] = { --formerly i: [0..8]
IF NOT (x<terminal.colorWidth AND y<terminal.colorHeight) THEN RETURN;
w ← MIN[w,terminal.colorWidth-x]; h ← MIN[h,terminal.colorHeight-y];
IF full THEN FullRect[x,y,w,h,i,i,i] --gray value
ELSE ARect[x,y,w,h,i];
};
SetUpColors: PROCEDURE = BEGIN
OPEN Terminal;
k: CARDINAL ← Basics.BITSHIFT[1,bpp]; -- number of pixel values
r,g,b: [0..256);
Alter: PROC[c: [0..256)] RETURNS[[0..256)] = INLINE { RETURN[255-(255-c)/2] };
IF full THEN {
FOR n: CARDINAL IN [0..256) DO
r ← MyRandom[256]; g ← MyRandom[256]; b ← MyRandom[256];
SetRedMap[terminal, g,r]; SetGreenMap[terminal, b,g]; SetBlueMap[terminal, r,b]; --scrambler
ENDLOOP;
}
ELSE {
FOR i: CARDINAL IN [0..k) DO
r ← MyRandom[256]; g ← MyRandom[256]; b ← MyRandom[256];
Terminal.SetColor[vt: terminal, aChannelValue: i, bChannelValue: 0, red: r, green: g, blue: b];
Terminal.SetColor[vt: terminal, aChannelValue: i, bChannelValue: 1, red: Alter[r], green: Alter[g], blue: Alter[b]];
ENDLOOP;
};
END;
Positive: PROC = {
IF NOT full THEN RETURN;
FOR i: CARDINAL IN[0..256) DO
Terminal.SetRedMap[terminal, i, i];
Terminal.SetGreenMap[terminal, i, i];
Terminal.SetBlueMap[terminal, i, i];
ENDLOOP;
};
HalfPositive: PROC = {
i: [0..256] ← 0;
IF NOT full THEN RETURN;
FOR j: CARDINAL IN[128..256) DO
Terminal.SetRedMap[terminal, j,i];
Terminal.SetGreenMap[terminal, j,i];
Terminal.SetBlueMap[terminal, j,i];
i← i+2;
ENDLOOP;
};
MyRandom: PROCEDURE [max: CARDINAL] RETURNS [CARDINAL] = INLINE BEGIN
RETURN[Random[] MOD max];
END;
SetGray: PROC[g: [0..256)] = { grayword ← MakeGray[g] };
MakeGray: PROC[g: [0..256)] RETURNS[CARDINAL] = {
grayword: CARDINAL ← 0;
IF bpp#0 THEN {
ppw: CARDINAL ← 16/bpp; -- pixels per word
mask: CARDINAL ← Basics.BITNOT[Basics.BITSHIFT[177777B,bpp]];
g ← Basics.BITAND[g,mask];
THROUGH [0..ppw) DO grayword ← Basics.BITSHIFT[grayword,bpp] + g ENDLOOP;
};
RETURN[grayword];
};
InitBB: PROC[bbs: POINTER TO PrincOps.BBTableSpace] RETURNS[PrincOps.BBptr] = TRUSTED INLINE {
bb: PrincOps.BBptr ← PrincOpsUtils.AlignedBBTable[bbs];
bb^ ← [
dst: [word: NIL, bit: 0],
dstBpl: 0,
src: [word: @grayword, bit: 0],
srcDesc: [gray[[yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]]],
width: 0, height: 0,
flags: [disjoint: TRUE, gray: TRUE]
];
RETURN[bb];
};
FullRect: PROC[x,y,w,h: CARDINAL, r,g,b: [0..256)] = TRUSTED {
rgword: CARDINAL ← 256*r + g;
bbword: CARDINAL ← 256*b + b;
frameA: Terminal.FrameBuffer ~ terminal.GetColorFrameBufferA[];
frameB: Terminal.FrameBuffer ~ terminal.GetColorFrameBufferB[];
IF NOT full THEN RETURN;
bitmap A
bb.dst ← [word: frameA.base + LONG[y]*frameA.wordsPerLine + x, bit: 0];
bb.dstBpl ← 16*frameA.wordsPerLine;
bb.src ← [word: @rgword, bit: 0];
bb.width ← 16*w;
bb.height ← h;
bb.flags.dstFunc ← null;
PrincOpsUtils.BITBLT[bb];
bitmap B
bb.dst ← [word: frameB.base + LONG[y]*frameB.wordsPerLine + x/2, bit: 8*(x MOD 2)];
bb.dstBpl ← 16*frameB.wordsPerLine;
bb.src ← [word: @bbword, bit: bb.dst.bit];
bb.width ← 8*w;
bb.height ← h;
bb.flags.dstFunc ← null;
PrincOpsUtils.BITBLT[bb];
};
ARect: PROC[x,y,w,h: CARDINAL, i: [0..256), fn: PrincOps.DstFunc ← null] = TRUSTED {
iword: CARDINAL ← MakeGray[i];
xbit: CARDINAL ← Basics.BITSHIFT[x,lbpp];
frameA: Terminal.FrameBuffer ~ terminal.GetColorFrameBufferA[];
bb.dst ← [word: frameA.base + LONG[y]*frameA.wordsPerLine + xbit/16, bit: xbit MOD 16];
bb.dstBpl ← 16*frameA.wordsPerLine;
bb.src ← [word: @iword, bit: bb.dst.bit];
bb.width ← Basics.BITSHIFT[w,lbpp];
bb.height ← h;
bb.flags.dstFunc ← fn;
PrincOpsUtils.BITBLT[bb];
};
index: [0..256) ← 0;
Rectangle: PROC[lx,ty,rx,by: CARDINAL, fn: PrincOps.DstFunc ← null, clear: BOOLEANFALSE] = {
IF full THEN {
r,g,b: [0..256);
IF clear THEN r←g𡤋𡤀 ELSE {r ← MyRandom[256]; g ← MyRandom[256]; b ← MyRandom[256];};
FullRect[lx,ty,rx-lx,by-ty,r,g,b];
}
ELSE {
index ← IF clear THEN 0 ELSE (index + 1) MOD 256;
ARect[lx,ty,rx-lx,by-ty,index,fn];
IF clear AND bitmapB#NIL THEN BRectangle[lx,ty,rx,by,null,TRUE];
};
};
BRectangle: PROC[lx,ty,rx,by: CARDINAL, fn: PrincOps.DstFunc ← xor, clear: BOOLEANFALSE] = TRUSTED {
xbit: CARDINAL ← Basics.BITSHIFT[lx,lbppB];
black: CARDINALIF clear THEN 0 ELSE 177777B;
frameB: Terminal.FrameBuffer ~ terminal.GetColorFrameBufferB[];
bb.dst ← [word: frameB.base + LONG[ty]*frameB.wordsPerLine + xbit/16, bit: xbit MOD 16];
bb.dstBpl ← 16*frameB.wordsPerLine;
bb.src ← [word: @black, bit: 0];
bb.width ← Basics.BITSHIFT[(rx-lx),lbppB];
bb.height ← by-ty;
bb.flags.dstFunc ← fn;
PrincOpsUtils.BITBLT[bb];
};
RandomSplat: PROCEDURE [ckViewer: CKViewer] = {
screenX: CARDINAL = terminal.colorWidth;
screenY: CARDINAL = terminal.colorHeight;
XorRatio: CARDINAL = 3;
ty, ty2, lx, w, h: CARDINAL;
fn: PrincOps.DstFunc ← (IF MyRandom[XorRatio]=0 THEN xor ELSE null);
SetGray[MyRandom[256]];
IF sym THEN {
ty ← ty2 ← MyRandom[screenY/2];
lx ← MyRandom[screenX/2];
w ← MyRandom[screenX/2-lx];
h ← MyRandom[screenY/2-ty];
Rectangle[lx, ty, lx+w, ty+h, fn];
ty ← screenY/2+(screenY/2-ty)-h;
Rectangle[lx, ty, lx+w, ty+h, fn];
lx ← screenX/2+(screenX/2-lx)-w;
Rectangle[lx, ty, lx+w, ty+h, fn];
Rectangle[lx, ty2, lx+w, ty2+h, fn];
}
ELSE {
ty ← MyRandom[screenY];
lx ← MyRandom[screenX];
w ← MyRandom[screenX-lx];
h ← MyRandom[screenY-ty];
Rectangle[lx, ty, lx+w, ty+h, fn];
};
IF bitmapB#NIL THEN {
ty ← MyRandom[screenY];
lx ← MyRandom[screenX];
w ← MyRandom[screenX-lx];
h ← MyRandom[screenY-ty];
BRectangle[lx, ty, lx+w, ty+h];
};
IF ckViewer.state.slow THEN Wait[200]; -- slow mode
};
ShowConverge: PROCEDURE = {
hThick: CARDINAL ← terminal.colorHeight/300;
hStep: CARDINAL ← terminal.colorHeight/30;
vThick: CARDINAL ← terminal.colorHeight/300;
vStep: CARDINAL ← terminal.colorHeight/30;
IF full THEN Positive[] ELSE {
FOR i: CARDINAL IN[0..9) DO
Terminal.SetColor[vt: terminal, aChannelValue: i, red: testmap[i].r, green: testmap[i].g, blue: testmap[i].b];
ENDLOOP;
SetShowButtons[TRUE,FALSE,FALSE];
};
TestRect[0,0,terminal.colorWidth,terminal.colorHeight,black]; --black background
FOR xx: CARDINAL ← 0, xx+hStep UNTIL xx > terminal.colorWidth DO
TestRect[xx, 0, vThick, terminal.colorHeight, white];
ENDLOOP;
FOR v: CARDINAL ← 0, v+vStep UNTIL v > terminal.colorHeight DO
TestRect[0, v, terminal.colorWidth, hThick ,white];
ENDLOOP;
};
ShowBig: PROCEDURE [big: BOOLEAN, color: {red, green, blue}] = {
r,g,b: CARDINAL;
rectheight: CARDINAL ← terminal.colorHeight/16; --sixteen rectangles
cInc: CARDINALIF big THEN 20B ELSE 1;
maxIntensity: CARDINALIF full THEN 400B ELSE (Basics.BITSHIFT[1,bpp]);
groupSize: CARDINALMAX[16/maxIntensity,1];
groupIndex: CARDINAL ← 16/groupSize;
IF NOT full THEN SetShowButtons[TRUE,FALSE,FALSE] ELSE SetShowButtons[TRUE,TRUE,TRUE];
FOR gI: CARDINAL IN [0..groupIndex) DO
inten: CARDINAL ← gI*cInc;
SELECT color FROM
red => {r←inten; b←g𡤀};
green => {g←inten; b←r𡤀};
blue => {b←inten; r←g𡤀};
ENDCASE => ERROR;
IF full THEN {
Terminal.SetRedMap[terminal, gI, r];
Terminal.SetGreenMap[terminal, gI, g];
Terminal.SetBlueMap[terminal, gI, b];
}
ELSE Terminal.SetColor[vt: terminal, aChannelValue: gI, red: r, green: g, blue: b];
FOR x: CARDINAL IN [0..groupSize) DO
nextRect: CARDINAL ← gI*groupSize + x;
Rect[0,nextRect*rectheight,terminal.colorWidth,rectheight, gI];
ENDLOOP;
ENDLOOP;
};
ShowBigRed: PROCEDURE [big: BOOLEAN] = {
ShowBig[big, red];
};
ShowBigGreen: PROCEDURE [big: BOOLEAN] = {
ShowBig[big, green];
};
ShowBigBlue: PROCEDURE [big: BOOLEAN] = {
ShowBig[big, blue];
};
ShowCBars: PROCEDURE = {
graywidth: CARDINAL ← terminal.colorWidth/128; --this must integer divide evenly
grayheight: CARDINAL ← terminal.colorHeight/2; --this must integer divide evenly
cbarwidth: CARDINAL ← (terminal.colorWidth)/9; --this may truncate
cbarheight: CARDINAL ← terminal.colorHeight/2; --this must integer divide evenly
IF full THEN HalfPositive[] ELSE { --set up gray map
k: CARDINAL ← (Basics.BITSHIFT[1,bpp])/2; -- half the number of pixel values
FOR n: CARDINAL IN [0..k) DO
Terminal.SetColor[vt: terminal, aChannelValue: n+200B, red: n*2, green: n*2, blue: n*2]; --use top half of colormap. Only makes sense for 8 BPP
ENDLOOP;
};
FOR i: CARDINAL IN[0..9) DO --set up color bars
IF full THEN {Terminal.SetRedMap[terminal, i,testmap[i].r]; Terminal.SetGreenMap[terminal, i,testmap[i].g]; Terminal.SetBlueMap[terminal, i,testmap[i].b];}
ELSE Terminal.SetColor[vt: terminal, aChannelValue: i, red: testmap[i].r, green: testmap[i].g, blue: testmap[i].b]
ENDLOOP;
FOR x: CARDINAL IN [0..128) DO --gray wedge
Rect[x*graywidth, 0, graywidth, grayheight, x+128];
ENDLOOP;
FOR x: CARDINAL IN [0..8] DO --colorbars
Rect[x*cbarwidth, cbarheight, cbarwidth, cbarheight, x];
ENDLOOP;
SetShowButtons[TRUE,full,full];
};
NextRoll: PROCEDURE [] = {
OPEN Terminal;
r,g,b,r0,g0,b0: [0..256);
IF full THEN {
r0←GetRedMap[terminal, 0]; g0←GetGreenMap[terminal, 0]; b0←GetBlueMap[terminal, 0];
FOR i: CARDINAL IN[0..255) DO
r ← GetRedMap[terminal, i+1]; g ← GetGreenMap[terminal, i+1]; b ← GetBlueMap[terminal, i+1];
SetRedMap[terminal, i,r]; SetGreenMap[terminal, i,g]; SetBlueMap[terminal, i,b];
ENDLOOP;
SetRedMap[terminal, 255,r0]; SetGreenMap[terminal, 255,g0]; SetBlueMap[terminal, 255,b0];
}
ELSE {
[r0,g0,b0] ← Terminal.GetColor[vt: terminal, aChannelValue: 0];
FOR i: CARDINAL IN[0..255) DO
[r,g,b] ← Terminal.GetColor[vt: terminal, aChannelValue: i+1];
Terminal.SetColor[terminal,i,0,r,g,b];
ENDLOOP;
Terminal.SetColor[terminal,255,0,r0,g0,b0];
};
Wait[100];
};
NextScramble: PROCEDURE [] = {
SetUpColors[]; Wait[200];
};
background: INTEGER ← 0; -- initially black
ClearScreen: PROCEDURE = {
IF NOT full THEN {
Terminal.SetColor[terminal, 0, 0, background, background, background];
SetGray[0] }
ELSE {Terminal.SetGreenMap[terminal, 0,0]; Terminal.SetBlueMap[terminal, 0,0]; Terminal.SetRedMap[terminal, 0,0];};
Rectangle[lx: 0, ty: 0, rx: terminal.colorWidth, by: terminal.colorHeight, fn: null, clear: TRUE];
};
Wait: PROCEDURE[millisecs: CARDINAL] = INLINE {
Process.Pause[Process.MsecToTicks[millisecs]] };
Constant definitions (meanings described in InitRandom below)
defaultSeed: CARDINAL = 27183;
numCalls: INTEGER = 3;
Module state
a: ARRAY [0..55] OF CARDINAL;
Holds 55 random cardinals, to be returned by Random. (A[0] is wasted to make the
code generator produce better array accesses.)
p: INTEGER [0..55];
a[1..p-1] has not yet been returned by Random; p is [1..55] except within Random.
Procedures
InitRandom: PUBLIC PROC[seed: INTEGER] RETURNS[INTEGER] = {
The parameter seed determines the sequence generated by procedure Random below.
If seed=0, a default seed value is used to determine the starting point of the
sequence; if seed>0, seed is scaled if necessary and then used; if seed<0, a seed
value is derived from the system clock. In any case, the seed value actually used
(after scaling) is the integer value returned.
minSeed: CARDINAL = LAST[CARDINAL]/10;
g, gPrev, gSave: CARDINAL;
IF seed<=0 THEN seed ← defaultSeed;
Now scale the seed into the proper range (no log routine available...)
WHILE seed<minSeed DO seed ← seed*3 ENDLOOP;
Seed can't be too big since LAST[INTEGER] < LAST[CARDINAL]*(9/10)
The array a is initialized by placing seed in a[55], and scattering the values
(-1)**(i-1) * (F(i) - seed*F(i-1)) MOD maxRand, 0<i<55,
(where F(i) denotes the i-th Fibonacci number) throughout the rest of a. Then
the generating procedure RandomGen is called, numCalls times, to make things
sufficiently random.
a[55] ← gPrev ← seed;
g ← 1;
FOR i: INTEGER IN [1..54] DO
p ← (21*i) MOD 55;
a[p] ← gSave ← g; g ← gPrev-g; gPrev ← gSave;
ENDLOOP;
THROUGH [1..numCalls) DO
RandomGen[];
ENDLOOP;
Show a as being empty; first call to Random will call RandomGen again.
p ← 1;
RETURN[seed]
};--InitRandom
Random: PUBLIC PROC RETURNS[CARDINAL] = INLINE {
p ← p-1;
IF p=0 THEN { RandomGen[]; p ← 55 };
RETURN[a[p]]
};--Random
RandomGen: PROC = INLINE {
Additive random number generator using the recurrence y(n) = y(n-55) - y(n-24)
mod maxRand. See John F. Reiser, "Analysis of Additive Random Number Generators",
STAN-CS-77-601, March 1977, or Knuth Volume 2 (second edition.)
FOR i: INTEGER IN [1..24] DO
a[i] ← a[i] - a[i+31];
ENDLOOP;
FOR i: INTEGER IN [25..55] DO
a[i] ← a[i] - a[i-24];
ENDLOOP;
};--RandomGen
Choose: PUBLIC PROC[min, max: CARDINAL] RETURNS[CARDINAL--[min..max]--] = {
intervalLen: CARDINAL;
IF min > max THEN ERROR;
intervalLen ← max - min + 1; --is 0 when min=0, max=LAST[CARDINAL]
IF intervalLen = 0 THEN RETURN[Random[]];
DO
Draw a number in [0..LAST[CARDINAL]]. We want to reject this number if it lies in the
"odd interval" at the high end of this range (there is no odd interval if intervalLen
divides 2^16). The funny test below does it (claim). The average number of numbers drawn
is less than 2, and much closer to 1 for small intervalLen.
r, rem: CARDINAL;
Inline expansion of Random[];
p ← p-1;
IF p=0 THEN { RandomGen[]; p ← 55 };
r ← a[p];
rem ← r MOD intervalLen;
IF (r - rem) > LOOPHOLE[-LOOPHOLE[intervalLen,INTEGER],CARDINAL] THEN LOOP;
RETURN[min + rem];
ENDLOOP;
};--Choose
SetLogBitsPerPixel: PROC[n: [0..4)] RETURNS[BOOLEAN] = {
b: CARDINAL ← Basics.BITSHIFT[1,n];
mode: Terminal.ColorMode ← [FALSE,b,1];
IF NOT Terminal.LegalColorMode[terminal, mode] THEN {
mode.bitsPerPixelChannelB ← 0;
IF NOT Terminal.LegalColorMode[terminal, mode] THEN RETURN[FALSE];
};
[]←Terminal.SetColorMode[terminal, mode];
Terminal.TurnOnColorDisplay[terminal];
lbpp ← n; bpp ← b; full ← FALSE;
lbppB ← 0; bppB ← 1;
SetShowButtons[TRUE, TRUE, FALSE];
bitmapB ← terminal.GetColorFrameBufferB[];
ClearScreen[];
SetUpColors[];
RETURN[TRUE];
};
Set24BitsPerPixel: PROC = {
mode: Terminal.ColorMode ← [TRUE,0,0];
IF NOT Terminal.LegalColorMode[terminal, mode] THEN RETURN;
Process.SetPriority[Process.priorityNormal];
[]←Terminal.SetColorMode[terminal, mode];
Terminal.TurnOnColorDisplay[terminal];
lbpp ← 0; bpp ← 0; full ← TRUE;
SetShowButtons[TRUE, TRUE, FALSE];
bitmapB ← NIL;
ClearScreen[];
SetUpColors[];
Process.SetPriority[Process.priorityBackground];
};
Go: PUBLIC PROC [ckViewer: CKViewer] = {
[] ← InitRandom[0];
public ← ckViewer;
Terminal.TurnOnColorDisplay[terminal];
Terminal.TurnOffColorDisplay[terminal];
SELECT TRUE FROM
SetLogBitsPerPixel[3] => NULL;
SetLogBitsPerPixel[2] => NULL;
ENDCASE => {
MW.Append[message: "NO COLOR DISPLAY !!", clearFirst: TRUE];
MW.Blink[];
RETURN;
};
Process.SetPriority[Process.priorityBackground];
DO
IF ckViewer.state.quit THEN {
ClearScreen;
ViewerOps.DestroyViewer[ckViewer.container];
[]←Terminal.SetColorBitmapState[vt: terminal, newState: none, newMode: Terminal.GetColorMode[terminal], newVisibility: none];
EXIT;
};
IF ckViewer.state.testingPanel THEN LOOP; --turned off by FinalizeTest
IF ckViewer.state.bpp=1 AND bpp#1 THEN { [] ← SetLogBitsPerPixel[0];
SetSplat[] };
IF ckViewer.state.bpp=2 AND bpp#2 THEN { [] ← SetLogBitsPerPixel[1];
SetSplat[] };
IF ckViewer.state.bpp=4 AND bpp#4 THEN { [] ← SetLogBitsPerPixel[2];
SetSplat[] };
IF ckViewer.state.bpp=8 AND bpp#8 THEN { [] ← SetLogBitsPerPixel[3];
SetSplat[] };
IF ckViewer.state.bpp=24 AND NOT full THEN { Set24BitsPerPixel[];
SetSplat[] };
IF ckViewer.state.aToggle THEN {
SetShowButtons[NOT ashow, bshow,FALSE];
ckViewer.state.aToggle ← FALSE};
IF ckViewer.state.bToggle THEN {
SetShowButtons[ashow, NOT bshow,FALSE];
ckViewer.state.bToggle ← FALSE};
IF ckViewer.state.random THEN {
sym ← FALSE;
SetSplat[];
ClearScreen[];
ckViewer.state.random ← FALSE;
};
IF ckViewer.state.symmetric THEN {
sym ← TRUE; SetSplat[];
ClearScreen[];
ckViewer.state.symmetric ← FALSE};
IF NOT ckViewer.state.freeze THEN {
ckViewer.state.roll ← ckViewer.state.scramble ← FALSE; --only TRUE when frozen
SELECT TRUE FROM
ckViewer.state.testPattern => {
splat ← FALSE; ShowTPat[]; ckViewer.state.testPattern ← FALSE;
};
ckViewer.state.cbars => {ShowCBars[]; splat ← ckViewer.state.cbars ← FALSE};
ckViewer.state.converge => {ShowConverge[]; splat ← ckViewer.state.converge ← FALSE};
ckViewer.state.diag => {Diag[]; splat ← ckViewer.state.diag ← FALSE};
ckViewer.state.bigRed => {ShowBigRed[big: TRUE]; splat ← ckViewer.state.bigRed ← FALSE};
ckViewer.state.bigGreen => {ShowBigGreen[big: TRUE]; splat ← ckViewer.state.bigGreen ← FALSE};
ckViewer.state.bigBlue => {ShowBigBlue[big: TRUE]; splat ← ckViewer.state.bigBlue ← FALSE};
ckViewer.state.smallRed => {ShowBigRed[big: FALSE]; splat ← ckViewer.state.smallRed ← FALSE};
ckViewer.state.smallGreen => {ShowBigGreen[big: FALSE]; splat ← ckViewer.state.smallGreen ← FALSE};
ckViewer.state.smallBlue => {ShowBigBlue[big: FALSE]; splat ← ckViewer.state.smallBlue ← FALSE};
ENDCASE => IF splat THEN RandomSplat[ckViewer];
}
ELSE {
SELECT TRUE FROM
ckViewer.state.scramble => NextScramble[];
ckViewer.state.roll => NextRoll[];
ENDCASE => NULL;
};
ENDLOOP;
};
SetSplat: PROCEDURE [] = {
splat ← TRUE; SetShowButtons[ashow,bshow,FALSE];
CKViewerButtons.SetStaticButtons[public, IF sym THEN public.buttons.symmetricButton ELSE public.buttons.randomButton]
};
SetShowButtons: PROCEDURE [a, b, c: BOOL] = {
vis: Terminal.ChannelsVisible;
ashow𡤊 bshow𡤋
vis ← SELECT TRUE FROM
a AND b => all,
a AND NOT b => aOnly,
NOT a AND b => bOnly,
NOT a AND NOT b => none,
ENDCASE => ERROR;
Terminal.SetVisibility[vt: terminal, visibility: vis];
Buttons.SetDisplayStyle[public.buttons.aChanButtton, IF ashow THEN $WhiteOnBlack ELSE $BlackOnWhite];
Buttons.SetDisplayStyle[public.buttons.bChanButton, IF bshow THEN $WhiteOnBlack ELSE $BlackOnWhite];
};
SetUpPanelTest: PUBLIC PROCEDURE [ckViewer: CKViewer] = {
ckViewer.state.testingPanel ← TRUE;
Wait[2000]; --stupid synchronizer so main loop in Go will quit messing with screen
ClearScreen []; --FILL FIFOS WITH Zeroes
Terminal.SetVisibility[vt: terminal, visibility: all]; --so when ChannelOn glitches nothing bad will happen
Wait[36]; --be sure both a and b actually show
SetShowButtons[ashow,bshow,TRUE]; --restore ashow/bshow
};
public: CKViewer ← NIL;
TRUSTED { bb ← InitBB[@bbspace] };
END.