[comp.lang.smalltalk] Opaque Form hacks, better shape:fill *wanted*

frobozz@well.sf.ca.us (Jordan Bortz) (04/11/90)

I've been working on an animation package for the Tigre system, and
have run into a lack of code  as it were; before I write these
routines, I was wondering:

	Does anyone have a routine that copies a Form into an OpaqueForm, but
makes the inner white bits WHITE instead of transparent?
	(ala COPY MASK in resedit)

	Of course, that could easily be written with one of two routines, so:

	What about a routine to list all the bits enclosed by the larges 
	single-closed-curve in a rectangle, or:

	A Better shape:fil routine that works faster and chews up less
memory...

		Thanks,
			Jordan

---
See you at MacWorld! :=)

phil@abccam.abcl.co.uk (Phillip Yelland) (04/12/90)

From: frobozz@well.sf.ca.us (Jordan Bortz)
>	A Better shape:fil (sic.) routine....

Well, here's something that might be of interest:
`Fraid I put it together late one night after a party (what, pose?--me, pose?),
so I can't attest to its quality---you should be able to improve it
significantly....

--Phil

P.S. The valueAt: hack is fairly specific to the monochrome, 32-bit Smalltalk
that we use.

---Cut---

!Form methodsFor: 'image manipulation'!

fillFrom: seed rule: rule mask: mask

	"Fill a bounded region encompassing seed with the rule and mask
	given"
	"Try: 
		Form exampleSketch. 
		Display 
			fillFrom: Sensor waitClickButton 
			rule: Form over 
			mask: Form gray"
	| copy stack x y rightX lastTop lastBottom top bottom fillBitBlt blackBitBlt | 

	copy _ self deepCopy.					"To track filled regions"
	stack _ OrderedCollection new: 100.	"For seeds"
	stack addLast: seed.
	fillBitBlt _ BitBlt 
		destForm: self
		sourceForm: nil
		halftoneForm: mask
		combinationRule: rule
		destOrigin: 0@0
		sourceOrigin: 0@0
		extent: 0@0
		clipRect: self boundingBox.
	blackBitBlt _ BitBlt 
		destForm: copy
		sourceForm: nil
		halftoneForm: Form black
		combinationRule: Form over
		destOrigin: 0@0
		sourceOrigin: 0@0
		extent: 0@0
		clipRect: self boundingBox.

	[stack isEmpty] whileFalse: [			"While lines still to be filled"
		x _ stack last x.
		y _ stack last y.
		stack removeLast.

		"Find the right-hand end of the scan-line"
		[x < self width and: [(copy valueAt: x@y) = 0]] whileTrue: [
			x _ x+1].

		rightX _ x.						"Save the right-hand end"
		x _ x-1.

		"Go left; seed rightmost pixels of scan-lines above and below"
		lastTop _ lastBottom _ 1.
		[x >= 0 and: [(copy valueAt: x@y) = 0]] whileTrue: [
			top _ y < 0 ifTrue: [1] ifFalse: [self valueAt: x@(y-1)].
			bottom _ y > self height ifTrue: [1] ifFalse: [
							self valueAt: x@(y+1)].

			"Check for unfilled scan-lines top and bottom"
			(lastTop = 1 and: [top = 0]) ifTrue: [
				stack addLast: x@(y-1)].
			(lastBottom = 1 and: [bottom = 0]) ifTrue: [
				stack addLast: x@(y+1)].

			lastBottom _ bottom.
			lastTop _ top.
			x _ x-1].

		"Fill this scan-line"
		x _ x+1.
		fillBitBlt destRect: (x@y corner: rightX@(y+1)); copyBits.
		blackBitBlt destRect: (x@y corner: rightX@(y+1)); copyBits]! !

!Form methodsFor: 'pattern'!

valueAt: aPoint

	"Query whether a bit is on or off.... answer with 1 if the color at coordinate aPoint 
	is black in the receiver and 0 if the color is white at coordinate aPoint"

	^((bits at: aPoint y*(width + 31 // 32 * 2)+(aPoint x//16+1)) 
		bitShift: 0-(aPoint x\\16)) bitAnd: 1! !