<> <> DIRECTORY BitBlt, Buttons, ViewerOps, CKViewerPanel, CKViewerButtons, ColorDisplay, GraphicsColor, MessageWindow, Inline, Real, Process USING [MsecToTicks, Pause]; CKViewerOps: PROGRAM IMPORTS BitBlt, Buttons, ColorDisplay, Inline, Real, Process, MessageWindow, CKViewerButtons, ViewerOps EXPORTS CKViewerButtons, CKViewerPanel = BEGIN OPEN MW: MessageWindow; CKViewer: TYPE = CKViewerButtons.CKViewer; CKViewerState: TYPE = CKViewerButtons.CKViewerState; sym: BOOLEAN _ FALSE; bbspace: BitBlt.BBTableSpace; bb: BitBlt.BBptr _ InitBB[@bbspace]; grayword: CARDINAL _ 0; bitmap,bitmapB: LONG POINTER _ NIL; wpl,wplB: CARDINAL _ 0; width,height: CARDINAL _ 0; lbpp,lbppB: CARDINAL _ 0; -- log (base 2) bits per pixel bpp,bppB: CARDINAL _ 0; -- bits per pixel full: BOOLEAN _ FALSE; ashow,bshow: BOOLEAN _ TRUE; splat: BOOLEAN _ TRUE; cornerSize: CARDINAL _ 4; cornerColor: CARDINAL _ 8; Triple: TYPE = RECORD[r,g,b: [0..256)]; testmap: ARRAY[0..8] OF Triple _ [ [127,127,127], -- gray (background) [ 0, 0, 0], -- black [255, 0, 0], -- red [ 0,255, 0], -- green [255,255, 0], -- yellow [ 0, 0,255], -- blue [255, 0,255], -- magenta [ 0,255,255], -- cyan [255,255,255] -- white ]; Diag: PROC [] = { <> Bham: PROC [fx,fy,lx,ly: INTEGER, color: [0..8]] = { <> 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_fx+xi; yy_fy+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; }; black: [0..8] = 1; --testmap[1] is black white: [0..8] = 8; --testmap[8] is white iWidth: INTEGER _ width; iHeight: INTEGER _ height; 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 ColorDisplay.SetColor[pixelA: i, r: testmap[i].r, g: testmap[i].g, b: testmap[i].b]; ENDLOOP; SetShowButtons[TRUE,FALSE,FALSE]; }; TestRect[0,0,width,height,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 ColorDisplay.SetColor[pixelA: i, r: testmap[i].r, g: testmap[i].g, b: testmap[i].b]; ENDLOOP; SetShowButtons[TRUE,FALSE,FALSE]; }; <> TestRect[0,0,width,height,0]; <> { s: CARDINAL = cornerSize; c: CARDINAL = cornerColor; -- color TestRect[0,0,s,s,c]; TestRect[width-s,0,s,s,c]; TestRect[0,height-s,s,s,c]; TestRect[width-s,height-s,s,s,c]; }; <> 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; <> 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> bb.dst _ [word: ColorDisplay.baseA + LONG[y]*ColorDisplay.wplA + x, bit: 0]; bb.dstBpl _ 16*ColorDisplay.wplA; bb.src _ [word: @rgword, bit: 0]; bb.width _ 16*w; bb.height _ h; bb.flags.dstFunc _ null; BitBlt.BITBLT[bb]; <> bb.dst _ [word: ColorDisplay.baseB + LONG[y]*ColorDisplay.wplB + x/2, bit: 8*(x MOD 2)]; bb.dstBpl _ 16*ColorDisplay.wplB; bb.src _ [word: @bbword, bit: bb.dst.bit]; bb.width _ 8*w; bb.height _ h; bb.flags.dstFunc _ null; BitBlt.BITBLT[bb]; }; ARect: PROC[x,y,w,h: CARDINAL, i: [0..256), fn: BitBlt.DstFunc _ null] = { iword: CARDINAL _ MakeGray[i]; xbit: CARDINAL _ Inline.BITSHIFT[x,lbpp]; bb.dst _ [word: ColorDisplay.baseA + LONG[y]*ColorDisplay.wplA + xbit/16, bit: xbit MOD 16]; bb.dstBpl _ 16*ColorDisplay.wplA; bb.src _ [word: @iword, bit: bb.dst.bit]; bb.width _ Inline.BITSHIFT[w,lbpp]; bb.height _ h; bb.flags.dstFunc _ fn; BitBlt.BITBLT[bb]; }; index: [0..256) _ 0; Rectangle: PROC[lx,ty,rx,by: CARDINAL, fn: BitBlt.DstFunc _ null, clear: BOOLEAN _ FALSE] = { IF full THEN { r,g,b: [0..256); IF clear THEN r_g_b_0 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: BitBlt.DstFunc _ xor, clear: BOOLEAN _ FALSE] = { xbit: CARDINAL _ Inline.BITSHIFT[lx,lbppB]; black: CARDINAL _ IF clear THEN 0 ELSE 177777B; bb.dst _ [word: bitmapB + LONG[ty]*wplB + xbit/16, bit: xbit MOD 16]; bb.dstBpl _ 16*wplB; bb.src _ [word: @black, bit: 0]; bb.width _ Inline.BITSHIFT[(rx-lx),lbppB]; bb.height _ by-ty; bb.flags.dstFunc _ fn; BitBlt.BITBLT[bb]; }; RandomSplat: PROCEDURE [ckViewer: CKViewer] = { screenX: CARDINAL = width; screenY: CARDINAL = height; XorRatio: CARDINAL = 3; ty, ty2, lx, w, h: CARDINAL; fn: BitBlt.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 = { black: [0..8] = 1; --testmap[1] is black white: [0..8] = 8; --testmap[8] is white hThick: CARDINAL _ height/300; hStep: CARDINAL _ height/30; vThick: CARDINAL _ height/300; vStep: CARDINAL _ height/30; IF full THEN Positive[] ELSE { FOR i: CARDINAL IN[0..9) DO ColorDisplay.SetColor[pixelA: i, r: testmap[i].r, g: testmap[i].g, b: testmap[i].b]; ENDLOOP; SetShowButtons[TRUE,FALSE,FALSE]; }; TestRect[0,0,width,height,black]; --black background FOR xx: CARDINAL _ 0, xx+hStep UNTIL xx > width DO TestRect[xx, 0, vThick, height, white]; ENDLOOP; FOR v: CARDINAL _ 0, v+vStep UNTIL v > height DO TestRect[0, v, width, hThick ,white]; ENDLOOP; }; ShowBig: PROCEDURE [big: BOOLEAN, color: GraphicsColor.Color] = { r,g,b: CARDINAL; rectheight: CARDINAL _ height/16; --sixteen rectangles cInc: CARDINAL _ IF big THEN 20B ELSE 1; maxIntensity: CARDINAL _ IF full THEN 400B ELSE (Inline.BITSHIFT[1,bpp]); groupSize: CARDINAL _ MAX[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 GraphicsColor.red => {r_inten; b_g_0}; GraphicsColor.green => {g_inten; b_r_0}; GraphicsColor.blue => {b_inten; r_g_0}; ENDCASE => ERROR; IF full THEN { OPEN ColorDisplay; SetRedMap[gI,r]; SetGreenMap[gI,g]; SetBlueMap[gI,b];} ELSE ColorDisplay.SetColor[pixelA: gI, pixelB: 0, r: r, g: g, b: b]; FOR x: CARDINAL IN [0..groupSize) DO nextRect: CARDINAL _ gI*groupSize + x; Rect[0,nextRect*rectheight,width,rectheight, gI]; ENDLOOP; ENDLOOP; }; ShowBigRed: PROCEDURE [big: BOOLEAN] = { ShowBig[big, GraphicsColor.red]; }; ShowBigGreen: PROCEDURE [big: BOOLEAN] = { ShowBig[big, GraphicsColor.green]; }; ShowBigBlue: PROCEDURE [big: BOOLEAN] = { ShowBig[big, GraphicsColor.blue]; }; ShowCBars: PROCEDURE = { graywidth: CARDINAL _ width/128; --this must integer divide evenly grayheight: CARDINAL _ height/2; --this must integer divide evenly cbarwidth: CARDINAL _ (width)/9; --this may truncate cbarheight: CARDINAL _ height/2; --this must integer divide evenly IF full THEN HalfPositive[] ELSE { --set up gray map k: CARDINAL _ (Inline.BITSHIFT[1,bpp])/2; -- half the number of pixel values FOR n: CARDINAL IN [0..k) DO ColorDisplay.SetColor[pixelA: n+200B, pixelB: 0, r: n*2, g: n*2, b: 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 {ColorDisplay.SetRedMap[i,testmap[i].r]; ColorDisplay.SetGreenMap[i,testmap[i].g]; ColorDisplay.SetBlueMap[i,testmap[i].b];} ELSE ColorDisplay.SetColor[pixelA: i, r: testmap[i].r, g: testmap[i].g, b: 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 ColorDisplay; r,g,b,r0,g0,b0: [0..256); IF full THEN { r0_GetRedMap[0]; g0_GetGreenMap[0]; b0_GetBlueMap[0]; FOR i: CARDINAL IN[0..255) DO r _ GetRedMap[i+1]; g _ GetGreenMap[i+1]; b _ GetBlueMap[i+1]; SetRedMap[i,r]; SetGreenMap[i,g]; SetBlueMap[i,b]; ENDLOOP; SetRedMap[255,r0]; SetGreenMap[255,g0]; SetBlueMap[255,b0]; } ELSE { [r0,g0,b0] _ ColorDisplay.GetColor[0]; FOR i: CARDINAL IN[0..255) DO [r,g,b] _ ColorDisplay.GetColor[i+1]; ColorDisplay.SetColor[i,0,r,g,b]; ENDLOOP; ColorDisplay.SetColor[255,0,r0,g0,b0]; }; Wait[100]; }; NextScramble: PROCEDURE [] = { SetUpColors[]; Wait[200]; }; background: INTEGER _ 0; -- initially black ClearScreen: PROCEDURE = { IF NOT full THEN { ColorDisplay.SetColor[0, 0, background, background, background]; SetGray[0] } ELSE {ColorDisplay.SetGreenMap[0,0]; ColorDisplay.SetBlueMap[0,0]; ColorDisplay.SetRedMap[0,0];}; Rectangle[lx: 0, ty: 0, rx: width, by: height, fn: null, clear: TRUE]; }; Wait: PROCEDURE[millisecs: CARDINAL] = INLINE { Process.Pause[Process.MsecToTicks[millisecs]] }; <> defaultSeed: CARDINAL = 27183; numCalls: INTEGER = 3; <> a: ARRAY [0..55] OF CARDINAL; <> <> p: INTEGER [0..55]; <> <> InitRandom: PUBLIC PROC[seed: INTEGER] RETURNS[INTEGER] = { <> <> <0, seed is scaled if necessary and then used; if seed<0, a seed>> <> <<(after scaling) is the integer value returned.>> minSeed: CARDINAL = LAST[CARDINAL]/10; g, gPrev, gSave: CARDINAL; IF seed<=0 THEN seed _ defaultSeed; <> WHILE seed> <> <<(-1)**(i-1) * (F(i) - seed*F(i-1)) MOD maxRand, 0> <<(where F(i) denotes the i-th Fibonacci number) throughout the rest of a. Then>> <> <> 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; <> 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 { <> <> <> 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 <> <<"odd interval" at the high end of this range (there is no odd interval if intervalLen>> <> <> r, rem: CARDINAL; <> 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 _ Inline.BITSHIFT[1,n]; mode: ColorDisplay.Mode _ [FALSE,b,1]; IF NOT ColorDisplay.HasMode[mode] THEN { mode.bitsPerPixelB _ 0; IF NOT ColorDisplay.HasMode[mode] THEN RETURN[FALSE]; }; IF NOT ColorDisplay.SetMode[mode] THEN ERROR; lbpp _ n; bpp _ b; full _ FALSE; lbppB _ 0; bppB _ 1; SetShowButtons[TRUE, TRUE, FALSE]; width _ ColorDisplay.width; height _ ColorDisplay.height; bitmap _ ColorDisplay.baseA; wpl _ ColorDisplay.wplA; bitmapB _ ColorDisplay.baseB; wplB _ ColorDisplay.wplB; ClearScreen; SetUpColors; ColorDisplay.TurnOn[]; RETURN[TRUE]; }; Set24BitsPerPixel: PROC = { mode: ColorDisplay.Mode _ [TRUE,0,0]; IF NOT ColorDisplay.HasMode[mode] THEN RETURN; IF NOT ColorDisplay.SetMode[mode] THEN ERROR; lbpp _ 0; bpp _ 0; full _ TRUE; bitmap _ NIL; bitmapB _ NIL; wpl _ 0; SetShowButtons[TRUE, TRUE, FALSE]; width _ ColorDisplay.width; height _ ColorDisplay.height; ClearScreen[]; ColorDisplay.TurnOn[]; }; Go: PUBLIC PROC [ckViewer: CKViewer] = { [] _ InitRandom[0]; public _ ckViewer; SELECT TRUE FROM SetLogBitsPerPixel[3] => NULL; SetLogBitsPerPixel[2] => NULL; ENDCASE => { MW.Append[message: "NO COLOR DISPLAY !!", clearFirst: TRUE]; MW.Blink[]; RETURN; }; DO IF ckViewer.state.quit THEN { ClearScreen; ViewerOps.DestroyViewer[ckViewer.container]; []_ColorDisplay.SetMode[ColorDisplay.disconnected]; 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; IF NOT ColorDisplay.SetMode[ColorDisplay.disconnected] THEN ERROR; }; 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] = { ashow_a; bshow_b; ColorDisplay.Show[a,b,c]; 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 ColorDisplay.Show[TRUE,TRUE,TRUE]; --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; END.