BlobKineticImpl.mesa
Michael Plass, October 3, 1983 2:37 pm
DIRECTORY ImagerBasic, ImagerPixelMaps, ImagerFrameBuffer, Process, ImagerScanConverter, Random, Inline, ImagerStroke, ImagerConic, Real;
BlobKineticImpl: CEDAR PROGRAM
IMPORTS ImagerPixelMaps, ImagerFrameBuffer, Process, ImagerScanConverter, Random, Inline, ImagerStroke, ImagerConic, Real
~ TRUSTED BEGIN
identity: ImagerBasic.Transformation ~ [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, identity];
Pair: TYPE ~ ImagerBasic.Pair;
running: BOOLEANFALSE;
pauseTime: Process.Milliseconds ← 5;
type: {blob, polygon} ← blob;
maxStrokeWidth: INT ← 30;
parityFill: BOOLEANFALSE;
colorDisplay: ImagerPixelMaps.PixelMap ← ImagerFrameBuffer.ColorDisplay8[];
clippedDisplay: ImagerPixelMaps.PixelMap ← colorDisplay;
rCount: CARDINAL ← 0;
crosses: BOOLEANTRUE;
Shift: PROC [a: CARDINAL, c: INTEGER] RETURNS [CARDINAL] ~ CHECKED {RETURN [Inline.BITSHIFT[a, c]]};
BITAND: PROC [a, b: CARDINAL] RETURNS [CARDINAL] ~ CHECKED {RETURN [Inline.BITAND[a, b]]};
ChooseReal: PROC [max: INT] RETURNS [r: REAL] ~ CHECKED {
scale: CARDINAL ← 1;
rCount ← rCount + 1;
IF rCount = 0 THEN rCount ← 1;
UNTIL BITAND[rCount, scale] # 0 DO
scale ← scale + 1;
ENDLOOP;
r ← Random.Choose[0, max*scale];
r ← r/scale;
IF rCount MOD 7 = 0 THEN {
epsilon: REAL ← 1.0/(65536.0*65536.0);
UNTIL r+epsilon # r DO epsilon ← epsilon*2 ENDLOOP;
IF rCount MOD 5 = 0 THEN r ← r+epsilon ELSE r ← r-epsilon;
};
};
Init: PROC ~ CHECKED {
ImagerPixelMaps.Clear[colorDisplay];
[] ← Random.Init[];
running ← TRUE;
};
strokeEndChoices: ARRAY [0..2] OF ImagerBasic.StrokeEnd ~ [square, butt, round];
Run: PROC ~ CHECKED {
devicePath: ImagerScanConverter.DevicePath;
maxSampleValue: CARDINAL ~ Shift[1, Shift[1, colorDisplay.refRep.lgBitsPerPixel]]-1;
running ← TRUE;
TRUSTED {Process.SetPriority[Process.priorityBackground]};
WHILE running DO
s: ARRAY [0..15) OF REAL;
f: ARRAY [0..15) OF REAL;
BlobProc: SAFE PROC [move: PROC [s, f: REAL], line: PROC [s, f: REAL], curve: PROC [s1, f1, s2, f2, s3, f3: REAL]] ~ CHECKED {
move[s[0], f[0]];
FOR i: NAT ← 1, i+3 WHILE i<13 DO
curve[s[i], f[i], s[i+1], f[i+1], s[i+2], f[i+2]];
ENDLOOP;
curve[s[13], f[13], s[14], f[14], s[0], f[0]];
};
PolygonProc: SAFE PROC [move: PROC [s, f: REAL], line: PROC [s, f: REAL], curve: PROC [s1, f1, s2, f2, s3, f3: REAL]] ~ CHECKED {
move[s[0], f[0]];
FOR i: NAT IN [1..15) DO
line[s[i], f[i]];
ENDLOOP;
};
FOR i: NAT IN [0..15) DO
s[i] ← ChooseReal[colorDisplay.sSize];
f[i] ← ChooseReal[colorDisplay.fSize];
ENDLOOP;
IF type = blob THEN {
s[0] ← (s[1]+s[14])/2.0;
f[0] ← (f[1]+f[14])/2.0;
FOR i: NAT ← 3, i+3 WHILE i<15 DO
s[i] ← (s[i+1]+s[i-1])/2.0;
f[i] ← (f[i+1]+f[i-1])/2.0;
ENDLOOP;
devicePath ← ImagerScanConverter.CreatePath[BlobProc, clippedDisplay.Window, devicePath];
}
ELSE devicePath ← ImagerScanConverter.CreatePath[PolygonProc, clippedDisplay.Window, devicePath];
devicePath.ConvertToPixels[clippedDisplay, Random.Choose[0, maxSampleValue], parityFill];
Process.Pause[Process.MsecToTicks[pauseTime]];
ENDLOOP;
};
SF: TYPE ~ RECORD [
closed: BOOLEAN,
s: ARRAY [0..15) OF REAL,
f: ARRAY [0..15) OF REAL
];
PathMap: SAFE PROC[
data: REF,
move: PROC[p: Pair],
line: PROC[p: Pair],
curve: PROC[p1, p2, p3: Pair],
conic: PROC[p1, p2: Pair, r: REAL]
] ~ CHECKED {
sf: REF SFNARROW[data];
{OPEN sf^;
move[[s[0], f[0]]];
FOR i: NAT ← 1, i+3 WHILE i<13 DO
curve[[s[i], f[i]], [s[i+1], f[i+1]], [s[i+2], f[i+2]]];
ENDLOOP;
IF closed THEN curve[[s[13], f[13]], [s[14], f[14]], [s[0], f[0]]];
};
};
Spaghetti: PROC ~ CHECKED {
devicePath: ImagerScanConverter.DevicePath;
maxSampleValue: CARDINAL ~ Shift[1, Shift[1, colorDisplay.refRep.lgBitsPerPixel]]-1;
sf: REF SFNEW[SF];
running ← TRUE;
TRUSTED {Process.SetPriority[Process.priorityBackground]};
WHILE running DO
OPEN sf^;
closed ← Random.Choose[0, 1] = 0;
FOR i: NAT IN [0..15) DO
s[i] ← ChooseReal[colorDisplay.sSize];
f[i] ← ChooseReal[colorDisplay.fSize];
ENDLOOP;
s[0] ← (s[1]+s[14])/2.0;
f[0] ← (f[1]+f[14])/2.0;
FOR i: NAT ← 3, i+3 WHILE i<15 DO
s[i] ← (s[i+1]+s[i-1])/2.0;
f[i] ← (f[i+1]+f[i-1])/2.0;
ENDLOOP;
devicePath ← ImagerStroke.DevicePathFromStroke[
pathMap: PathMap,
pathData: sf,
clientToDevice: identity,
width: Random.Choose[1, maxStrokeWidth],
strokeEnd: strokeEndChoices[Random.Choose[0, 2]],
closed: closed,
clipBox: [0,0,10000,10000],
scratch: devicePath
];
devicePath.ConvertToPixels[clippedDisplay, Random.Choose[0, maxSampleValue], parityFill];
Process.Pause[Process.MsecToTicks[pauseTime]];
ENDLOOP;
};
ArcData: TYPE ~ RECORD [
s: ARRAY [0..3) OF REAL,
f: ARRAY [0..3) OF REAL,
vs: ARRAY [0..3) OF REAL,
vf: ARRAY [0..3) OF REAL
];
ArcMap: PROC [
data: REF,
move: PROC[p: Pair],
line: PROC[p: Pair],
curve: PROC[p1, p2, p3: Pair],
conic: PROC[p1, p2: Pair, r: REAL]
] ~ CHECKED {
arcData: REF ArcData ← NARROW[data];
move[[arcData.s[0],arcData.f[0]]];
ImagerConic.FromArc[[arcData.s[0],arcData.f[0]], [arcData.s[1],arcData.f[1]], [arcData.s[2],arcData.f[2]], conic]
};
Cross: PROC [s, f: REAL] ~ CHECKED {
IF crosses THEN {
maxSampleValue: CARDINAL ~ Shift[1, Shift[1, colorDisplay.refRep.lgBitsPerPixel]]-1;
si: INTEGER ~ Real.RoundLI[s];
fi: INTEGER ~ Real.RoundLI[f];
colorDisplay.Fill[[si-3, fi-3, 6, 6], maxSampleValue];
colorDisplay.Fill[[si-5, fi-1, 10, 2], 0];
colorDisplay.Fill[[si-1, fi-5, 2, 10], 0];
};
};
Rainbow: PROC [speed: REAL ← 5.0] ~ CHECKED {
devicePath: ImagerScanConverter.DevicePath;
maxSampleValue: CARDINAL ~ Shift[1, Shift[1, colorDisplay.refRep.lgBitsPerPixel]]-1;
arcData: REF ArcData ← NEW[ArcData];
ChangeControlPoints: SAFE PROC ~ CHECKED {
OPEN arcData^;
FOR i: NAT IN [0..3) DO
s[i] ← s[i] + vs[i];
IF s[i] > colorDisplay.sSize+colorDisplay.sMin THEN {
s[i] ← colorDisplay.sSize+colorDisplay.sMin - (s[i]-colorDisplay.sSize-colorDisplay.sMin);
vs[i] ← -vs[i];
};
IF s[i] < colorDisplay.sMin THEN {
s[i] ← colorDisplay.sMin+(colorDisplay.sMin-s[i]);
vs[i] ← -vs[i];
};
f[i] ← f[i] + vf[i];
IF f[i] > colorDisplay.fSize+colorDisplay.fMin THEN {
f[i] ← colorDisplay.fSize+colorDisplay.fMin - (f[i]-colorDisplay.fSize-colorDisplay.fMin);
vf[i] ← -vf[i];
};
IF f[i] < colorDisplay.fMin THEN {
f[i] ← colorDisplay.fMin+(colorDisplay.fMin-f[i]);
vf[i] ← -vf[i];
};
ENDLOOP;
};
FOR i: NAT IN [0..3) DO
arcData.s[i] ← colorDisplay.sSize/2;
arcData.f[i] ← colorDisplay.fSize/2;
arcData.vs[i] ← ((Random.Choose[0, 2000]-1000)/1000.0)*speed;
arcData.vf[i] ← ((Random.Choose[0, 2000]-1000)/1000.0)*speed;
ENDLOOP;
running ← TRUE;
TRUSTED {Process.SetPriority[Process.priorityBackground]};
WHILE running DO
ChangeControlPoints[];
devicePath ← ImagerStroke.DevicePathFromStroke[
pathMap: ArcMap,
pathData: arcData,
clientToDevice: identity,
width: maxStrokeWidth,
strokeEnd: butt,
closed: FALSE,
clipBox: [0,0,10000,10000],
scratch: devicePath
];
devicePath.ConvertToPixels[clippedDisplay, Random.Choose[0, maxSampleValue], parityFill];
Cross[arcData.s[0], arcData.f[0]]; Cross[arcData.s[1], arcData.f[1]]; Cross[arcData.s[2], arcData.f[2]];
Process.Pause[Process.MsecToTicks[pauseTime]];
ENDLOOP;
};
SwimRec: TYPE ~ RECORD [pxlValue: CARDINAL, running, blob: BOOLEANTRUE, window: ImagerPixelMaps.DeviceRectangle];
Swim: PROC [speed: REAL ← 5.0, pxlValue: CARDINAL ← 23, window: ImagerPixelMaps.DeviceRectangle ← [0, 0, 480, 640], blob: BOOLEANTRUE] RETURNS [data: REF SwimRec] ~ TRUSTED {
data ← NEW [SwimRec];
data.pxlValue ← pxlValue;
data.window ← window;
data.running ← TRUE;
data.blob ← blob;
Process.Detach[FORK SwimProcess[speed, data]];
};
SwimProcess: PROC [speed: REAL ← 5.0, data: REF SwimRec] ~ CHECKED {
devicePath: ImagerScanConverter.DevicePath;
maxSampleValue: CARDINAL ~ Shift[1, Shift[1, colorDisplay.refRep.lgBitsPerPixel]]-1;
s: ARRAY [0..15) OF REAL;
f: ARRAY [0..15) OF REAL;
vs: ARRAY [0..15) OF REAL;
vf: ARRAY [0..15) OF REAL;
ChangeControlPoints: SAFE PROC ~ CHECKED {
FOR i: NAT IN [0..15) DO
s[i] ← s[i] + vs[i];
IF s[i] > data.window.sSize+data.window.sMin THEN {
s[i] ← data.window.sSize+data.window.sMin - (s[i]-data.window.sSize-data.window.sMin);
vs[i] ← -vs[i];
};
IF s[i] < data.window.sMin THEN {
s[i] ← data.window.sMin+(data.window.sMin-s[i]);
vs[i] ← -vs[i];
};
f[i] ← f[i] + vf[i];
IF f[i] > data.window.fSize+data.window.fMin THEN {
f[i] ← data.window.fSize+data.window.fMin - (f[i]-data.window.fSize-data.window.fMin);
vf[i] ← -vf[i];
};
IF f[i] < data.window.fMin THEN {
f[i] ← data.window.fMin+(data.window.fMin-f[i]);
vf[i] ← -vf[i];
};
ENDLOOP;
};
FOR i: NAT IN [0..15) DO
s[i] ← colorDisplay.sSize/2;
f[i] ← colorDisplay.fSize/2;
vs[i] ← ((Random.Choose[0, 2000]-1000)/1000.0)*speed;
vf[i] ← ((Random.Choose[0, 2000]-1000)/1000.0)*speed;
ENDLOOP;
TRUSTED {Process.SetPriority[Process.priorityBackground]};
WHILE data.running DO
BlobProc: SAFE PROC [move: PROC [s, f: REAL], line: PROC [s, f: REAL], curve: PROC [s1, f1, s2, f2, s3, f3: REAL]] ~ CHECKED {
move[s[0], f[0]];
FOR i: NAT ← 1, i+3 WHILE i<13 DO
curve[s[i], f[i], s[i+1], f[i+1], s[i+2], f[i+2]];
ENDLOOP;
curve[s[13], f[13], s[14], f[14], s[0], f[0]];
ChangeControlPoints[];
s[0] ← (s[1]+s[14])/2.0;
f[0] ← (f[1]+f[14])/2.0;
FOR i: NAT ← 3, i+3 WHILE i<15 DO
s[i] ← (s[i+1]+s[i-1])/2.0;
f[i] ← (f[i+1]+f[i-1])/2.0;
ENDLOOP;
move[s[0], f[0]];
FOR i: NAT ← 1, i+3 WHILE i<13 DO
curve[s[i], f[i], s[i+1], f[i+1], s[i+2], f[i+2]];
ENDLOOP;
curve[s[13], f[13], s[14], f[14], s[0], f[0]];
};
PolygonProc: SAFE PROC [move: PROC [s, f: REAL], line: PROC [s, f: REAL], curve: PROC [s1, f1, s2, f2, s3, f3: REAL]] ~ CHECKED {
move[s[0], f[0]];
FOR i: NAT IN [1..15) DO
line[s[i], f[i]];
ENDLOOP;
ChangeControlPoints[];
move[s[0], f[0]];
FOR i: NAT IN [1..15) DO
line[s[i], f[i]];
ENDLOOP;
};
IF data.blob THEN {
devicePath ← ImagerScanConverter.CreatePath[BlobProc, clippedDisplay.Window, devicePath];
}
ELSE devicePath ← ImagerScanConverter.CreatePath[PolygonProc, clippedDisplay.Window, devicePath];
devicePath.ConvertToPixels[clippedDisplay, data.pxlValue, TRUE, [xor, null]];
Process.Pause[Process.MsecToTicks[pauseTime]];
ENDLOOP;
};
END.