From VisualWorks®, Release 5i.1 of January 3, 2000 on November 13, 2004 at 3:06:03 am Colours Smalltalk Core.Object false none mySize image palette As yet unclassified Colours class random midpoint: aRandom from: end1 to: end2 "Pick a random number between two end values (inclusive)." | small big | (end1 < end2) ifTrue: [ small := end1. big := end2. ] ifFalse: [ small := end2. big := end1. ]. ^ (aRandom next * (big - small + 1)) floor + small. Colours class instance creation x: xInteger y: yInteger c: cInteger "Answer a new colours object of the specified size." | coloursObject | coloursObject := self new. coloursObject make_palette: cInteger. coloursObject make_image: (Point x: xInteger y: yInteger). ^coloursObject Colours creation fillRand: aRandom col: col from: endtop to: endbottom "Recursively fill one column." "Used to bootstrap the recursive area fill." "Also used to fudge our way out of ?x2 rectangles." | middleY | (endtop + 1 = endbottom) ifFalse: [ "Set the dot in the middle." middleY := ((endbottom - endtop) / 2 + endtop) floor. self x: col y: middleY put: (Colours midpoint: aRandom from: (self x: col y: endtop) to: (self x: col y: endbottom)). "Go fill the two new sub-columns." self fillRand: aRandom col: col from: endtop to: middleY. self fillRand: aRandom col: col from: middleY to: endbottom. ] fillRand: aRandom row: row from: endleft to: endright "Recursively fill one row." "Used to bootstrap the recursive area fill." "Also used to fudge our way out of ?x2 rectangles." | middleX | (endleft + 1 = endright) ifFalse: [ "Set the dot in the middle." middleX := ((endright - endleft) / 2 + endleft) floor. self x: middleX y: row put: (Colours midpoint: aRandom from: (self x: endleft y: row) to: (self x: endright y: row)). "Go fill the two new sub-rows." self fillRand: aRandom row: row from: endleft to: middleX. self fillRand: aRandom row: row from: middleX to: endright. ] fillRand: aRandom top: endtop bottom: endbottom left: endleft right: endright "Recursively fill the area." | middleY middleX centre1 centre2 | ((endleft + 1 = endright) & (endtop + 1 = endbottom)) ifTrue: [ "This is just a 2x2 square. Nothing to do." ] ifFalse: [ (endleft + 1 = endright) ifTrue: [ "This is just a 2x? rectangle. Fill in some vertical space." self fillRand: aRandom col: endright from: endtop to: endbottom. ] ifFalse: [ (endtop + 1 = endbottom) ifTrue: [ "This is just a ?x2 rectangle. Fill in some horizontal space." self fillRand: aRandom row: endbottom from: endleft to: endright. ] ifFalse: [ "Wide open space; something to sink our recursive teeth into..." "Set the dot half way along the bottom row." middleX := ((endright - endleft) / 2 + endleft) floor. self x: middleX y: endbottom put: (Colours midpoint: aRandom from: (self x: endleft y: endbottom) to: (self x: endright y: endbottom)). "Set the dot half way along the right column." middleY := ((endbottom - endtop) / 2 + endtop) floor. self x: endright y: middleY put: (Colours midpoint: aRandom from: (self x: endright y: endtop) to: (self x: endright y: endbottom)). "Set the dot in the middle (midpoint of two midpoints)." centre1 := Colours midpoint: aRandom from: (self x: middleX y: endtop) to: (self x: middleX y: endbottom). centre2 := Colours midpoint: aRandom from: (self x: endright y: middleY) to: (self x: endleft y: middleY). self x: middleX y: middleY put: (Colours midpoint: aRandom from: centre1 to: centre2). "Go fill the four new quadrants." self fillRand: aRandom top: endtop bottom: middleY left: endleft right: middleX. self fillRand: aRandom top: middleY bottom: endbottom left: endleft right: middleX. self fillRand: aRandom top: endtop bottom: middleY left: middleX right: endright. self fillRand: aRandom top: middleY bottom: endbottom left: middleX right: endright. ] ] ] make_image: aPoint "Compute a grid of recursive colours of the specified size." | randomGenerator | self setSize: aPoint. randomGenerator := Random new. "Flip a coin to determine which diagonally opposite corners get the master colours." randomGenerator next > 0.5 ifTrue: [ self x: 0 y: 0 put: 0. self x: self cols - 1 y: self rows - 1 put: palette size - 1. self x: self cols - 1 y: 0 put: (Colours midpoint: randomGenerator from: 0 to: palette size - 1). self x: 0 y: self rows - 1 put: (Colours midpoint: randomGenerator from: 0 to: palette size - 1). ] ifFalse: [ self x: 0 y: self rows - 1 put: 0. self x: self cols - 1 y: 0 put: palette size - 1. self x: 0 y: 0 put: (Colours midpoint: randomGenerator from: 0 to: palette size - 1). self x: self cols - 1 y: self rows - 1 put: (Colours midpoint: randomGenerator from: 0 to: palette size - 1). ]. "Draw the top row and left column." self fillRand: randomGenerator row: 0 from: 0 to: self cols - 1. self fillRand: randomGenerator col: 0 from: 0 to: self rows - 1. "Now we have the top edge, the left edge, and the bottom/right dot." "We are all setup to fill the remaining area." self fillRand: randomGenerator top: 0 bottom: self rows - 1 left: 0 right: self cols - 1. make_palette: n "Create a palette of n equidistant colours spanning a range between" "two randomly picked master colours." | c1r c1g c1b c2r c2g c2b r g b colourList count ratio aColour randomGenerator | randomGenerator := Random new. c1r := c1b := c1g := 0. c2r := c2b := c2g := 0. [(c1r-c2r) abs + (c1b-c2b) abs + (c1g-c2g) abs >= 1] whileFalse: [ c1r := randomGenerator next. c1g := randomGenerator next. c1b := randomGenerator next. c2r := randomGenerator next. c2g := randomGenerator next. c2b := randomGenerator next. ]. colourList := Array new: n. count := 0. n timesRepeat: [ ratio := count/(n-1). r := c1r * ratio + (c2r * (1 - ratio)). g := c1g * ratio + (c2g * (1 - ratio)). b := c1b * ratio + (c2b * (1 - ratio)). aColour := ColorValue red: r green: g blue: b. count := count + 1. colourList at: count put: aColour. ]. palette := MappedPalette withColors: colourList. open "Open the image in a window." ScheduledWindow new component: image; minimumSize: mySize; open Colours accessing cols "Answer the number of columns." ^mySize x rows "Answer the number of rows." ^mySize y setSize: aPoint "Set the X/Y size of this object." mySize := aPoint. image := Image extent: aPoint depth: 8 bitsPerPixel: 8 palette: palette. "grid := ByteArray new: (self cols) * (self rows) withAll: 0." x: xInt y: yInt "Get the pixel at point X/Y." ^image atPoint: (Point x: xInt y: yInt). x: xInt y: yInt put: newPixel "Set a pixel at point X/Y." image atPoint: (Point x: xInt y: yInt) put: newPixel.