DIRECTORY Graphics, GraphicsOps, Random, ViewerBlast, ViewerOps; ViewerBlastImpl: CEDAR PROGRAM IMPORTS Graphics, GraphicsOps, Random, ViewerOps EXPORTS ViewerBlast = BEGIN OPEN ViewerBlast; Context: TYPE = Graphics.Context; rows, cols: INTEGER = 8; pieces: ARRAY [0 .. rows) OF ARRAY [0 .. cols) OF Piece; Piece: TYPE = RECORD [ bmw: IntBox, loc: IntPt, --screen coords of center of piece speed: IntPt]; screenBitmap: Bitmap _ GraphicsOps.ScreenBitmap[]; screenBox: IntBox _ [0, 0, screenBitmap.width, screenBitmap.height]; screenContext: Context _ Graphics.NewContext[]; RayToBox: PROC [from, to: IntPt, bloated: IntBox] RETURNS [edge: IntPt] = BEGIN dx: INTEGER _ to.x - from.x; dy: INTEGER _ to.y - from.y; IF dy = 0 THEN RETURN [ [x: IF dx = 0 THEN ERROR ELSE IF dx > 0 THEN bloated.xmin + bloated.dx ELSE bloated.xmin, y: to.y]]; IF dx = 0 THEN RETURN [ [x: to.x, y: IF dy = 0 THEN ERROR ELSE IF dy > 0 THEN bloated.ymin + bloated.dy ELSE bloated.ymin]]; edge.y _ ((INT[IF dx > 0 THEN bloated.xmin + bloated.dx ELSE bloated.xmin] - from.x) * dy)/dx + from.y; edge.y _ IF dy > 0 THEN MIN[edge.y, bloated.ymin + bloated.dy] ELSE MAX[edge.y, bloated.ymin]; edge.x _ ((INT[IF dy > 0 THEN bloated.ymin + bloated.dy ELSE bloated.ymin] - from.y) * dx)/dy + from.x; edge.x _ IF dx > 0 THEN MIN[edge.x, bloated.xmin + bloated.dx] ELSE MAX[edge.x, bloated.xmin]; END; BloatBox: PROC [box: IntBox, dx, dy: INTEGER] RETURNS [bloated: IntBox] = { RETURN [[box.xmin - dx, box.ymin - dy, box.dx + 2*dx, box.dy + 2*dy]]}; SGN: PROC [x: INTEGER] RETURNS [sx: INTEGER] = {sx _ IF x > 0 THEN 1 ELSE IF x < 0 THEN -1 ELSE 0}; Ceiling: PROC [num, den: INTEGER] RETURNS [quot: INTEGER] = {quot _ num/den; quot _ quot + SGN[num]/SGN[den]; quot _ (num - quot*den)/den + quot}; --what this actually does is round away from 0-- Blast: PUBLIC PROC [ bm: Bitmap, bmw: IntBox, --bitmap coords (y measured from top) lowerLeft: IntPt, --of where initial bitmap appears on screen convergeOn: IntPt _ [], --screen point for all centers to emanate from preSteps: INTEGER _ 3, speedChooser: SpeedChooser _ NIL, initial: BOOLEAN _ TRUE, backwards: BOOLEAN _ FALSE] = BEGIN row, col: INTEGER; hcheight, hcwidth: INTEGER; step, steps: INTEGER _ 0; bloated: IntBox; edge: IntPt; hcheight _ bmw.dy/(rows*2); hcwidth _ bmw.dx/(cols*2); bloated _ BloatBox[screenBox, hcwidth+1, hcheight+1]; Graphics.SetCP[screenContext, 0, 0]; [] _ Graphics.SetPaintMode[screenContext, invert]; FOR row IN [0 .. rows) DO FOR col IN [0 .. cols) DO loc: IntPt; needs: INTEGER; pieces[row][col].bmw.xmin _ (bmw.dx*col + cols-1)/cols; pieces[row][col].bmw.ymin _ (bmw.dy*row + rows-1)/rows; pieces[row][col].bmw.dx _ (bmw.dx*(col+1) + cols-1)/cols - pieces[row][col].bmw.xmin; pieces[row][col].bmw.dy _ (bmw.dy*(row+1) + rows-1)/rows - pieces[row][col].bmw.ymin; pieces[row][col].loc _ loc _ [ lowerLeft.x + hcwidth + pieces[row][col].bmw.xmin, lowerLeft.y + bmw.dy - (hcheight + pieces[row][col].bmw.ymin)]; IF speedChooser = NIL THEN BEGIN edge _ RayToBox[convergeOn, loc, bloated]; pieces[row][col].speed _ [ Ceiling[loc.x - convergeOn.x, preSteps], Ceiling[loc.y - convergeOn.y, preSteps]]; END ELSE BEGIN pieces[row][col].speed _ speedChooser[row, col]; edge _ [bloated.xmin, bloated.ymin]; IF pieces[row][col].speed.x > 0 THEN edge.x _ edge.x + bloated.dx; IF pieces[row][col].speed.y > 0 THEN edge.y _ edge.y + bloated.dy; END; needs _ IF pieces[row][col].speed.x = 0 THEN IF pieces[row][col].speed.y = 0 THEN ERROR ELSE Ceiling[edge.y - loc.y, pieces[row][col].speed.y] ELSE IF pieces[row][col].speed.y = 0 THEN Ceiling[edge.x - loc.x, pieces[row][col].speed.x] ELSE MIN[ Ceiling[edge.y - loc.y, pieces[row][col].speed.y], Ceiling[edge.x - loc.x, pieces[row][col].speed.x]]; steps _ MAX[steps, needs]; ENDLOOP; ENDLOOP; IF backwards THEN BEGIN FOR row IN [0 .. rows) DO FOR col IN [0 .. cols) DO pieces[row][col].loc.x _ pieces[row][col].loc.x + pieces[row][col].speed.x * (steps); pieces[row][col].loc.y _ pieces[row][col].loc.y + pieces[row][col].speed.y * (steps); pieces[row][col].speed.x _ -pieces[row][col].speed.x; pieces[row][col].speed.y _ -pieces[row][col].speed.y; ENDLOOP; ENDLOOP; END; FOR step IN [0 .. steps) DO drawOld, drawNew: BOOLEAN; drawOld _ step # 0 OR (initial AND NOT backwards); drawNew _ step # (steps-1) OR (initial AND backwards); FOR row IN [0 .. rows) DO FOR col IN [0 .. cols) DO IF drawOld THEN GraphicsOps.DrawBitmap[ self: screenContext, bitmap: bm, w: pieces[row][col].bmw.dx, h: pieces[row][col].bmw.dy, x: pieces[row][col].bmw.xmin, y: pieces[row][col].bmw.ymin, xorigin: hcwidth + pieces[row][col].bmw.xmin - pieces[row][col].loc.x, yorigin: hcheight + pieces[row][col].bmw.ymin + pieces[row][col].loc.y]; pieces[row][col].loc.x _ pieces[row][col].loc.x + pieces[row][col].speed.x; pieces[row][col].loc.y _ pieces[row][col].loc.y + pieces[row][col].speed.y; IF drawNew THEN GraphicsOps.DrawBitmap[ self: screenContext, bitmap: bm, w: pieces[row][col].bmw.dx, h: pieces[row][col].bmw.dy, x: pieces[row][col].bmw.xmin, y: pieces[row][col].bmw.ymin, xorigin: hcwidth + pieces[row][col].bmw.xmin - pieces[row][col].loc.x, yorigin: hcheight + pieces[row][col].bmw.ymin + pieces[row][col].loc.y]; ENDLOOP; ENDLOOP; ENDLOOP; lastSteps _ steps; END; lastSteps: INTEGER; rate1: INTEGER _ 50; rate2: INTEGER _ 100; RandomSpeed: PUBLIC SpeedChooser = { speed _ [0, 0]; WHILE ABS[speed.x] < rate1 AND ABS[speed.y] < rate1 DO speed _ [Random.Choose[-rate2, rate2], Random.Choose[-rate2, rate2]] ENDLOOP}; Choose: PROC [min, max: INTEGER] RETURNS [choice: INTEGER] = {choice _ Random.Choose[min - (1+max-min), max]; IF choice < min THEN choice _ choice - 2*min + 1}; CopyViewer: PUBLIC PROC [v: Viewer, window: IntBox _ [], windowed: BOOLEAN _ FALSE] RETURNS [bm: Bitmap, x, y: INTEGER] = BEGIN c: Context; w, h: INTEGER; bm _ GraphicsOps.NewBitmap[v.ww, v.wh]; c _ GraphicsOps.NewContextFromBitmap[bm]; Graphics.SetCP[c, 0, 0]; IF windowed THEN { [x, y] _ ViewerOps.UserToScreenCoords[v, window.xmin, window.ymin]; w _ window.dx; h _ window.dy; } ELSE IF v.parent = NIL THEN { x _ v.wx; y _ v.wy; w _ v.ww; h _ v.wh} ELSE { [x, y] _ ViewerOps.UserToScreenCoords[v.parent, v.wx, v.wy]; w _ v.ww; h _ v.wh; IF v.parent.class.coordSys = top THEN y _ y - v.wh}; GraphicsOps.DrawBitmap[self: c, bitmap: screenBitmap, w: w, h: h, x: x, y: screenBox.ymin + screenBox.dy - (y + h), xorigin: x, yorigin: screenBox.ymin + screenBox.dy - (y)]; END; BlastViewer: PROC [ v: Viewer, convergeOn: IntPt _ [], preSteps: INTEGER _ 3, speedChooser: SpeedChooser _ NIL, initial: BOOLEAN _ TRUE, backwards: BOOLEAN _ FALSE] = BEGIN left, bottom: INTEGER; bm: Bitmap; [bm, left, bottom] _ CopyViewer[v]; Blast[bm: bm, bmw: [0, 0, v.ww, v.wh], lowerLeft: [left, bottom], convergeOn: convergeOn, preSteps: preSteps, speedChooser: speedChooser, initial: initial, backwards: backwards]; END; DrawBitmap: PUBLIC PROC [ self: Context, bitmap: Bitmap, w, h: INTEGER, -- width and height of rectangle x, y: INTEGER _ 0, -- upper left corner of rectangle xorigin, yorigin: INTEGER _ 0 -- point to be aligned with cp ] = BEGIN IF x < 0 THEN {w _ w + x; x _ 0}; IF y < 0 THEN {h _ h + y; y _ 0}; IF w <= 0 OR h <= 0 THEN RETURN; GraphicsOps.DrawBitmap[self: self, bitmap: bitmap, w: w, h: h, x: x, y: y, xorigin: xorigin, yorigin: yorigin]; END; END. NViewerBlastImpl.Mesa Last Edited by: Spreitzer, August 7, 1983 1:53 pm สW– "cedar" style˜J™J™1J˜Icodešฯk œ7˜@K˜šะbxœœ˜Kšœ)˜0Kšœ˜—K˜Kšœœ ˜K˜Kšœ œ˜!K˜Kšœ œ˜K˜Kš œœ œœ œ˜8K˜šœœœ˜K˜ Kšœ ฯc"˜.K˜—K˜Kšœ2˜2KšœD˜DK˜/K˜šฯnœœ$œ˜IKš˜Kšœœ˜Kšœœ˜šœœœ˜šœœœ˜Kšœœœ˜-Kšœ˜—K˜ —šœœœ˜K˜ šœœœ˜Kšœœœ˜-Kšœ˜——Kš œ œœœœ+˜gKš œ œœœ$œœ˜^Kš œ œœœœ+˜gKš œ œœœ$œœ˜^Kšœ˜—K˜š œœœœ˜KKšœA˜G—K˜Kšะknœœœœœ œœœœœœ˜cK˜š  œœ œœœ˜;Kšœ˜Kšœœœ˜ Kšœ$˜$KšŸ0˜0—K˜š œœ˜šœ˜Kšœ ˜ Kšœ Ÿ%˜2KšœŸ+˜=KšœŸ.˜FKšœ œ˜Kšœœ˜!Kšœ œœ˜Kšœ œœ˜—Kš˜Kšœ œ˜Kšœœ˜Kšœ œ˜K˜K˜ K˜K˜Kšœ5˜5K˜$K˜2šœœ ˜šœœ ˜K˜ Kšœœ˜K˜7K˜7K˜UK˜Ušœ˜Kšœ2˜2Kšœ?˜?—šœœ˜Kš˜Kšœ*˜*šœ˜Kšœ(˜(Kšœ)˜)—Kš˜—šœ˜ Kšœ0˜0K˜$Kšœœ˜BKšœœ˜BKšœ˜—šœ˜šœ˜š˜šœ˜Kšœ˜ Kšœ2˜6——š˜šœ˜Kšœ2˜6šœœ˜ Kšœ2˜2Kšœ3˜3—————Kšœœ˜Kšœ˜—Kšœ˜—šœ ˜Kš˜šœœ ˜šœœ ˜KšœU˜UKšœU˜UKšœ5˜5Kšœ5˜5Kšœ˜—Kšœ˜—Kšœ˜—šœœ˜Kšœœ˜Kšœœ œœ ˜2Kšœœ œ ˜6šœœ ˜šœœ ˜šœ œ˜'K˜K˜ K˜K˜K˜K˜K˜FKšœH˜H—K˜KK˜Kšœ œ˜'K˜K˜ K˜K˜K˜K˜K˜FKšœH˜H—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜Kšœ˜—K˜Kšœ œ˜K˜Kšœœ˜Kšœœ˜K˜š  œœ˜$Kšœ˜š œœœœ˜6KšœD˜DKšœ˜ ——K˜š  œœ œœ œ˜