DIRECTORY Basics, BasicTime, Buttons, ColorDisplayFace, FS, Histograms, IdleBackdoor, Imager, ImagerBox, ImagerColor, ImagerColorMap, ImagerDitherContext, ImagerFont, ImagerInterpress, ImagerPath, ImagerPixelMap, ImagerTerminal, ImagerTransformation, IO, Menus, PrincOps, Process, Random, Real, RealFns, Rope, Terminal, ThisMachine, TIPUser, UserProfile, Vector2, ViewerClasses, ViewerOps; PolyKal: CEDAR MONITOR IMPORTS BasicTime, Buttons, ColorDisplayFace, FS, IdleBackdoor, Imager, ImagerBox, ImagerColor, ImagerColorMap, ImagerDitherContext, ImagerFont, ImagerPath, ImagerTerminal, ImagerTransformation, IO, Process, Random, Real, RealFns, Rope, Terminal, ThisMachine, UserProfile = { ROPE: TYPE = Rope.ROPE; VEC: TYPE = Vector2.VEC; Viewer: TYPE = ViewerClasses.Viewer; PixelMap: TYPE = ImagerPixelMap.PixelMap; Font: TYPE = ImagerFont.Font; ConstantColor: TYPE = Imager.ConstantColor; Transformation: TYPE = ImagerTransformation.Transformation; ColorMapEntryList: TYPE = LIST OF ImagerColorMap.MapEntry; Sgn: TYPE = INTEGER[-1 .. 1]; TextData: TYPE = RECORD [ texts: TextList, numTexts: NAT, totalProbability: REAL]; TextList: TYPE = LIST OF Text; Text: TYPE = RECORD [ text: ROPE, bounds: Imager.Box, cumProb: REAL ]; Control: TYPE = REF ControlPrivate; ControlPrivate: TYPE = RECORD [ shouldGo: BOOL _ FALSE, ipSize: REAL--meters-- _ Imager.metersPerInch*3.0, wantIP, hold: BOOL _ FALSE, symmetry: CARDINAL _ 8, sExp, vExp: REAL _ 0.5, upTextMin: Milliseconds _ 10*OneSecond, upTextMax: Milliseconds _ 60*OneSecond, downTextMin: Milliseconds _ 1*OneSecond, downTextMax: Milliseconds _ 6*OneSecond, doText: BOOL _ FALSE, pausePeriod: Process.Ticks _ 0, holdPeriod: Process.Ticks _ Process.MsecToTicks[500], runningPriority: Process.Priority _ Process.priorityBackground, AtATime: NAT _ 64, retraces: NAT _ 1 ]; td: TextData; font: Font _ NIL; rs: Random.RandomStream _ Random.Create[seed: -1]; Milliseconds: TYPE = INT; OneSecond: Milliseconds = 1000; Root3Quarters: REAL _ RealFns.SqRt[0.75]; black: Imager.Color _ Imager.black; white: Imager.Color _ Imager.white; going: BOOL _ FALSE; machineName: ROPE _ ThisMachine.Name[]; ctl: Control _ NEW [ControlPrivate _ []]; ButtonControl: PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift, control: BOOL _ FALSE] = BEGIN OPEN ctl; SELECT control FROM FALSE => { shouldGo _ NOT going; IF shouldGo AND OKToGo[] THEN { symmetry _ rs.ChooseInt[2, 8]*2; TRUSTED {Process.Detach[FORK Viewit[]]}; }; }; TRUE => { SELECT mouseButton FROM red => wantIP _ TRUE; yellow => NULL; blue => hold _ NOT hold; ENDCASE => ERROR; }; ENDCASE => ERROR; END; StopGoing: ENTRY PROC = {going _ FALSE}; OKToGo: ENTRY PROC RETURNS [go: BOOL] = {IF go _ NOT going THEN going _ TRUE}; StopViewing: PROC RETURNS [BOOL] = {OPEN ctl; RETURN [NOT shouldGo]}; Kalidle: PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift, control: BOOL _ FALSE] = { OPEN ctl; symmetry _ rs.ChooseInt[2, 8]*2; [] _ IdleBackdoor.UseAlternateVT[vtProc: DoForVT, logout: NOT control]; }; vtContext: Imager.Context; GiveVTContext: PROC [to: PROC [context: Imager.Context]] = {to[vtContext]}; Viewit: PROC = { OPEN ctl; TRUSTED { Process.SetPriority[runningPriority]; }; VTWork[Terminal.Current[], StopViewing !UNWIND => StopGoing[]]; StopGoing[]; }; DoForVT: PROC [vt: Terminal.Virtual] = { context: Imager.Context; vt.Select[]; [] _ vt.SetBWBitmapState[allocated]; [] _ vt.SetBWBitmapState[displayed]; context _ ImagerTerminal.BWContext[vt: vt, pixelUnits: TRUE]; Imager.SetColor[context, Imager.white]; Imager.MaskRectangle[context, [0, 0, vt.bwWidth, vt.bwHeight]]; VTWork[vt, KeyTyped]; }; KeyTyped: PROC RETURNS [stop: BOOL] = { stop _ IdleBackdoor.KeyTyped[IdleBackdoor.defaultKeyFilter]}; VTWork: PROC [vt: Terminal.Virtual, Stop: PROC RETURNS [BOOL]] = { OPEN ctl; width, height: INTEGER; mapEntries: ColorMapEntryList _ ImagerColorMap.StandardColorMapEntries[8]; SimpleSet: PROC [a, b: Terminal.ChannelValue _ 0, red, green, blue: Terminal.ColorValue, shared: BOOL _ TRUE] = { Terminal.SetColor[vt: vt, aChannelValue: a, bChannelValue: b, red: red, green: green, blue: blue]; }; WithContext: PROC = { IF useImagerColorMap THEN ImagerColorMap.Change[vt, WithVT] ELSE WithVT[SimpleSet]; }; WithVT: PROC [set: ImagerColorMap.MapProc] = { vt _ vt; FOR cml: ColorMapEntryList _ mapEntries, cml.rest WHILE cml # NIL DO set[a: cml.first.mapIndex, b: 0, red: cml.first.red, green: cml.first.green, blue: cml.first.blue]; ENDLOOP; vt _ vt; Dewit[giveContext: GiveVTContext, xp0: 0, yp0: 0, xp1: width, yp1: height, Stop: Stop, vt: vt]; vt _ vt; }; [vtContext, width, height] _ StartDeviceAndPM[vt]; IF useImagerDitherContext THEN ImagerDitherContext.DoWithDitherMap[context: vtContext, mapEntries: mapEntries, action: WithContext] ELSE WithContext[]; }; useImagerDitherContext: BOOL _ TRUE; useImagerColorMap: BOOL _ TRUE; upText, downText, T: Milliseconds _ 0; curText: Text; cto: Vector2.VEC; cts: REAL; TwoToThe: ARRAY [0 .. 15] OF CARDINAL = [ 00001H, 00002H, 00004H, 00008H, 00010H, 00020H, 00040H, 00080H, 00100H, 00200H, 00400H, 00800H, 01000H, 02000H, 04000H, 08000H]; Dewit: PROC [giveContext: PROC [to: PROC [context: Imager.Context]], xp0, yp0, xp1, yp1: INTEGER, Stop: PROC RETURNS [BOOL], vt: Terminal.Virtual] = { OPEN ctl; a: REAL--degrees-- = 360.0/symmetry; sinA: REAL = RealFns.SinDeg[a]; cosA: REAL = RealFns.CosDeg[a]; xSize: NAT --x size of 0th slice = MIN[ Real.Fix[(xp1 - xp0) * (SELECT symmetry MOD 4 FROM 0 => 1.0, 2 => cosA, ENDCASE => ERROR)], Real.Fix[(yp1 - yp0) / (IF symmetry = 4 THEN 1.0 ELSE MAX[ ImagerTransformation.Rotate[Real.Fix[(90 - a)/(2*a)]*2*a].Transform[[1.0, RealFns.TanDeg[a]]].y, ImagerTransformation.Rotate[Ceiling[(90 - a)/(2*a)]*2*a].Transform[[1.0, RealFns.TanDeg[a]]].y ])] ]/2; ySize: NAT = IF symmetry # 4 THEN Real.RoundI[xSize*RealFns.TanDeg[a]] ELSE xSize; center: VEC = [x: (xp0 + xp1)/2, y: (yp0 + yp1)/2]; toZero: Transformation = ImagerTransformation.Translate[[-center.x, -center.y]]; rotateCCW: Transformation = toZero.PostRotate[2*a].PostTranslate[center]; rotateCW: Transformation = toZero.PostRotate[-2*a].PostTranslate[center]; negateY: Transformation _ toZero.PostScale2[[1.0, -1.0]].PostTranslate[center]; d0: REAL = sinA*center.x - cosA*center.y; PickText: PROC [T: Milliseconds] = { p: REAL _ Choose[0, td.totalProbability*0.999]; tl: TextList; FOR tl _ td.texts, tl.rest WHILE p > tl.first.cumProb DO NULL ENDLOOP; curText _ tl.first; upText _ T + rs.ChooseInt[upTextMin, upTextMax]; downText _ upText + rs.ChooseInt[downTextMin, downTextMax]; cts _ (xp1 - xp0)/(curText.bounds.xmax - curText.bounds.xmin)/2; cto _ [ x: Choose[ xp0 - cts*curText.bounds.xmin, xp1 - cts*curText.bounds.xmax], y: Choose[ yp0 - cts*curText.bounds.ymin, yp1 - cts*curText.bounds.ymax]]; }; DrawText: PROC [context: Imager.Context] = { InnerDoit: PROC = { context.SetXY[cto]; context.TranslateT[cto]; context.ScaleT[cts]; context.SetFont[font]; context.ShowRope[curText.text]; }; Imager.DoSave[context, InnerDoit]; }; prevUp: BOOL _ FALSE; outline: ImagerPath.Outline = NEW [ImagerPath.OutlineRep[symmetry]]; DrawInit: PROC [context: Imager.Context] = { Imager.SetColor[context, Imager.black]; Imager.MaskBox[context, [xp0, yp0, xp1, yp1]]; }; DrawDelta: PROC [context: Imager.Context] = { shouldUp: BOOL = (T >= upText) AND (T < downText); urVerts: CARDINAL = rs.ChooseInt[3, 7]; Generate: ImagerPath.PathProc = { first: BOOL _ TRUE; firstV, lastV: VEC; firstD, lastD: REAL; firstS, lastS: Sgn _ 0; See: PROC [v: VEC, d: REAL, sgn: Sgn] = { IF sgn*lastS < 0 THEN { perLast: REAL = d / REAL[d - lastD]; perCur: REAL = - lastD / REAL[d - lastD]; cross: VEC = [ x: perCur*v.x + perLast*lastV.x, y: perCur*v.y + perLast*lastV.y]; IF first THEN {first _ FALSE; moveTo[cross]} ELSE lineTo[cross]; } ELSE IF sgn >= 0 THEN { IF first THEN {first _ FALSE; moveTo[v]} ELSE lineTo[v]; }; }; FOR i: INT IN [1 .. urVerts] DO v: VEC = [ center.x + rs.ChooseInt[0, xSize], center.y + rs.ChooseInt[0, ySize]]; d: REAL = sinA*v.x - cosA*v.y - d0; sgn: Sgn = SGN[d]; IF i = 1 THEN {firstV _ v; firstD _ d; firstS _ sgn}; See[v, d, sgn]; lastV _ v; lastD _ d; lastS _ sgn; ENDLOOP; See[firstV, firstD, firstS]; }; tl: ImagerPath.TrajectoryList _ NIL; WHILE tl = NIL DO tl _ ImagerPath.TrajectoryListFromPath[Generate] ENDLOOP; outline[0] _ tl.first; IF tl.rest # NIL THEN ERROR; outline[1] _ TransformTrajectory[outline[0], negateY]; FOR i: INT IN (0 .. symmetry/2) DO outline[2*i+0] _ TransformTrajectory[outline[2*i-2], rotateCCW]; outline[2*i+1] _ TransformTrajectory[outline[2*i-1], rotateCW]; ENDLOOP; Imager.SetColor[context, PickColor[]]; Imager.MaskFillOutline[context, outline, TRUE]; IF doText AND shouldUp # prevUp THEN { Imager.SetColor[context, IF shouldUp THEN PickColor[] ELSE black]; DrawText[context]; prevUp _ shouldUp; }; IF T >= downText THEN PickText[T]; }; oldP: BasicTime.Pulses; PickText[T _ 0]; giveContext[DrawInit]; oldP _ BasicTime.GetClockPulses[]; FOR i: INT _ 0, i+1 WHILE NOT Stop[] DO newP: BasicTime.Pulses; IF hold THEN Process.Pause[holdPeriod] ELSE giveContext[DrawDelta]; IF pausePeriod # 0 THEN Process.Pause[pausePeriod]; FOR i: NAT IN [0 .. retraces) DO Terminal.WaitForBWVerticalRetrace[vt]; ENDLOOP; newP _ BasicTime.GetClockPulses[]; IF newP > oldP THEN { Dt: Milliseconds _ BasicTime.PulsesToMicroseconds[newP - oldP]/1000; T _ T + Dt}; oldP _ newP; ENDLOOP; oldP _ oldP; }; TransformTrajectory: PROC [traj: ImagerPath.Trajectory, m: Transformation] RETURNS [new: ImagerPath.Trajectory] = { Produce: ImagerPath.PathProc = { ImagerPath.MapTrajectory[traj, moveTo, lineTo, curveTo, conicTo, arcTo]; }; first: BOOL _ TRUE; Consume: PROC [t: ImagerPath.Trajectory] = { IF first THEN {first _ FALSE; new _ t} ELSE ERROR; }; ImagerPath.TrajectoriesFromPath[Produce, m, Consume]; }; PickColor: PROC RETURNS [color: ConstantColor] = { OPEN ctl; color _ ImagerColor.ColorFromRGB[ImagerColor.RGBFromHSV[[ S: RealFns.Power[rs.ChooseInt[0, 16384]/16384.0, sExp], V: RealFns.Power[rs.ChooseInt[0, 16384]/16384.0, vExp], H: rs.ChooseInt[0, 1023]/1024.0]]]; }; StartDeviceAndPM: PROC [vt: Terminal.Virtual] RETURNS [context: Imager.Context, width, height: INTEGER] = { OPEN ctl; bpp: INT = 8; fb: Terminal.FrameBuffer; IF ColorDisplayFace.displayType = none THEN [] _ ColorDisplayFace.SetDisplayType[profiledDisplayType]; [] _ Terminal.SetColorBitmapState[vt: vt, newState: displayed, newMode: [full: FALSE, bitsPerPixelChannelA: bpp, bitsPerPixelChannelB: 0], newVisibility: aOnly]; context _ ImagerTerminal.ColorContext[vt: vt, pixelUnits: TRUE]; IF vt.GetColorMode[].bitsPerPixelChannelA # bpp THEN ERROR; fb _ vt.GetColorFrameBufferA[]; width _ fb.width; height _ fb.height; }; profiledDisplayType: ColorDisplayFace.ColorDisplayType; FixC: PROC [r: REAL] RETURNS [c: CARDINAL] = {c _ Real.FixC[r]}; Floor: PROC [r: REAL] RETURNS [i: INT] = { d: INT _ 1 - Real.Fix[r]; i _ Real.Fix[r+d]-d}; Ceiling: PROC [r: REAL] RETURNS [i: INT] = { d: INT _ 1 + Real.Fix[r]; i _ Real.Fix[r-d]+d}; ReadTextData: PROC [fileName: ROPE] RETURNS [td: TextData] = { OPEN ctl; from: IO.STREAM _ FS.StreamOpen[fileName]; last: TextList _ NIL; td _ [ texts: NIL, numTexts: 0, totalProbability: 0]; DO prob: REAL; text: ROPE; this: TextList; [] _ from.SkipWhitespace[]; IF from.EndOf[] THEN EXIT; prob _ from.GetReal[]; text _ from.GetRopeLiteral[]; text _ Replace[text, "", machineName]; td.numTexts _ td.numTexts + 1; this _ LIST[ [ text: text, bounds: ImagerBox.BoxFromExtents[font.RopeBoundingBox[text]], cumProb: td.totalProbability _ td.totalProbability + prob] ]; IF last = NIL THEN td.texts _ this ELSE last.rest _ this; last _ this; ENDLOOP; from.Close[]; }; Choose: PROC [min, max: REAL] RETURNS [r: REAL] = {r _ min + (rs.ChooseInt[0, 10000]/1.0E4) * (max-min)}; Replace: PROC [in, what, with: ROPE] RETURNS [new: ROPE] = { start, len: INT; ousLen: INT _ what.Length[]; new _ in; WHILE (start _ new.Index[s2: what]) < (len _ new.Length[]) DO new _ new.Substr[len: start].Cat[with, new.Substr[start: start+ousLen, len: len - (start+ousLen)]]; ENDLOOP; }; CreateButton: PROC = { ctlButton _ Buttons.Create[info: [name: "pKal", column: static], proc: ButtonControl, documentation: "click to run/stop polygon kaleidoscope"]; }; ctlButton: Buttons.Button _ NIL; SGN: PROC [r: REAL] RETURNS [sgn: Sgn] = { sgn _ SELECT r FROM <0 => -1, =0 => 0, >0 => 1, ENDCASE => ERROR; }; NoteProfile: PROC [reason: UserProfile.ProfileChangeReason] --UserProfile.ProfileChangedProc-- = { displayTypeRope: ROPE _ UserProfile.Token["ColorDisplay.Type", "640x480"]; profiledDisplayType _ SELECT TRUE FROM displayTypeRope.Equal["1024x768", FALSE] => highResolution, displayTypeRope.Equal["640x480", FALSE] => standard, ENDCASE => standard; }; Start: PROC = { UserProfile.CallWhenProfileChanges[NoteProfile]; font _ ImagerFont.Find["Xerox/PressFonts/TimesRoman-MRR"]; td _ ReadTextData["Kal.texts"]; CreateButton[]; }; Start[]; }. abcdefghijklmnopqrstuvwxyz1234567890-=\[]_;',./ ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%~&*()+|{}^:"<>? abcdefghijklmnopqrstuvwxyz1234567890-=\[]_;',./ ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%~&*()+|{}^:"<>? ΘPolyKal.Mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last Edited by: Spreitzer, May 13, 1986 1:55:59 pm PDT INVARIANT going IFF there is a process running the kaleidoscope. Κώ– "cedar" style˜code™ Kšœ Οmœ1™Kšžœ˜ Kšœžœžœžœ˜*Kšœžœ˜˜Kšœžœ˜ K˜ K˜—šž˜Kšœžœ˜ Kšœžœ˜ K˜K˜Kšžœžœžœ˜K˜K˜K˜4Kšœ˜šœžœ˜K˜ Kšœ=˜=Kšœ=˜=—Kšžœžœžœžœ˜9K˜ Kšžœ˜—K˜ K˜—K˜š ‘œžœ žœžœžœ˜1K˜7—K˜š ‘œžœžœžœžœ˜