mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-05 08:30:14 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
651 lines
18 KiB
Plaintext
651 lines
18 KiB
Plaintext
;
|
|
; File: BitMaptoRegion.a
|
|
;
|
|
; Contains: FUNCTION BitMapToRegionGlue(region: RgnHandle;bMap: BitMap): OSErr;
|
|
;
|
|
; Given a region and bitmap, BitMapRgn makes the region a bounding
|
|
; region for the 'map. If it can't get memory it will return a
|
|
; Memory Manager-type error and an empty region gibbley. Note that
|
|
; the region might also be empty with no error (if the bounds is an
|
|
; empty rectangle or there are no 1 bits in the bitmap). Lastly,
|
|
; if the region would have to exceed 32K it returns a result of
|
|
; -500 (rgnTooBigErr).
|
|
;
|
|
; The bMap parameter may be a pointer to a bitmap, a pointer to a
|
|
; pixmap, or a pointer to a portBits field in a color grafport.
|
|
; In the latter two cases, if the pixmap is not 1-bit deep, an error
|
|
; result of -148 (pixmapTooDeepErr) is returned.
|
|
;
|
|
; (the nibble state machine idea is from the Finder MaskToRgn routine)
|
|
;
|
|
; Copyright: © 1988-1992 by Apple Computer, Inc. All rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM3> 10/28/92 SWC Changed the INCLUDEs to a LOAD of StandardEqu.d.
|
|
; <SM2> 10/26/92 CSS Change a short branch to a word branch.
|
|
; <2> 7/24/91 MH Added conditional wrapper(s) to prevent duplication of public
|
|
; interface declarations: rgnTooBigErr, pixmapTooDeepErr
|
|
;
|
|
|
|
LOAD 'StandardEqu.d'
|
|
|
|
IF (&TYPE('Debugging') = 'UNDEFINED') THEN
|
|
Debugging EQU 0 ;debugging flag (1 = TRUE)
|
|
ENDIF
|
|
|
|
;________________________________________________________________________________
|
|
;
|
|
; FUNCTION BitMapToRegionGlue(region: RgnHandle;bMap: BitMap): OSErr;
|
|
;
|
|
;________________________________________________________________________________
|
|
;
|
|
;Theory
|
|
; We scan each line of the bitmap and pump inversion points (ip's) into the region
|
|
; to put the areas with ones in the bitmap into the region and the areas
|
|
; with zeroes outside the region.
|
|
;
|
|
; In order to keep track of where we are in "inversion land" we use two
|
|
; techniques:
|
|
|
|
; The first is a scanline buffer which records the changes
|
|
; (zeroes to ones and vice versa) as we go. Wherever a change occurs (a
|
|
; 1 next to a 0 in the buffer) we need to put out an inversion point.
|
|
|
|
; The second is a togglin' flag which tells us whether we are "inverted" or not.
|
|
; Since we use a state machine in the innermost (nibble) loop to churn out
|
|
; ip's, the input to the state machine must be complemented if the flag is set.
|
|
|
|
; The loop stuff looks like this:
|
|
; outer line loop (grows handle in anticipation of worst case for next line)
|
|
; longword loop for current line (puts out inter-long ip's as needed)
|
|
; loop for 4 nibbles in current long (calls state maching for each nibble)
|
|
;
|
|
;________________________________________________________________________________
|
|
|
|
BitMapRgnTrap EQU $A8D7
|
|
UnimplementedTrap EQU $A89F
|
|
isCPort EQU 14 ;bit 14 in rowbytes means portBits in CGrafPort
|
|
|
|
MACRO
|
|
SafeDisposeHandle
|
|
MOVE.L A0,D0
|
|
BEQ.S @0
|
|
_DisposHandle
|
|
@0
|
|
ENDM
|
|
|
|
BitMapToRegionGlue PROC EXPORT
|
|
;let's check for the existence of the trap
|
|
MOVE.W #BitMapRgnTrap,D0
|
|
_GetTrapAddress newTool
|
|
MOVE.L A0,A1 ;stash address in A1
|
|
MOVE.W #UnimplementedTrap,D0
|
|
_GetTrapAddress newTool ;unimplemented trap is in A0
|
|
CMP.L A0,A1 ;unimplemented?
|
|
BEQ.S RunRAM ;skip if so
|
|
|
|
JMP (A1) ;go to _BitMapRgn
|
|
|
|
;the trap is unimplemented, run the RAM version
|
|
RunRAM
|
|
|
|
BMFrame RECORD {A6Link},DECR
|
|
result DS.W 1
|
|
|
|
paramTop EQU *
|
|
|
|
regionH DS.L 1
|
|
bMapPtr DS.L 1
|
|
|
|
paramSize EQU paramTop-*
|
|
|
|
return DS.L 1
|
|
A6Link DS.L 1
|
|
|
|
rowLongs DS.L 1 ;number of longwords per line
|
|
rightMask DS.L 1 ;mask for rightmost long of each line
|
|
slHandle DS.L 1 ;handle to scanline buffer
|
|
numLines DS.W 1 ;number of lines in bitmap
|
|
rowNumBytes DS.W 1 ;rowbytes from the bitmap
|
|
startSize DS.W 1 ;size of region at start of line
|
|
lastLineH DS.L 1 ;last line (zeroes) handle
|
|
|
|
handSize DS.L 1 ;size of handle (avoid calls to GetHandleSize)
|
|
max2Add DS.L 1 ;worst case for bytes we could add for next line
|
|
|
|
localSize EQU *
|
|
ENDR
|
|
|
|
WITH BMFrame
|
|
LINK A6,#localSize
|
|
MOVEM.L A2-A5/D3-D7,-(SP) ;save work registers
|
|
|
|
CLR.L slHandle(A6) ;no scanline handle, yet
|
|
CLR.W result(A6) ;function result presumed zero at start
|
|
|
|
MOVE.L regionH(A6),A0
|
|
MOVE.L (A0),A2
|
|
MOVEQ #0,D0
|
|
MOVE.W (A2),D0 ;get size of region
|
|
MOVE.L D0,handSize(A6) ;save it long
|
|
|
|
;get boundary rectangle so we can tell how to process the bitmap
|
|
|
|
MOVE.L bMapPtr(A6),A1 ;get bitmap pointer
|
|
MOVE.W rowBytes(A1), D0 ;rowbytes
|
|
BPL.S @1 ;it's a bitmap so go ahead
|
|
BTST #isCPort, D0 ;is this a ptr to portBits?
|
|
BEQ.S @2 ;nope; it's a ptr to a pixmap
|
|
MOVE.L baseAddr(A1), A0 ;get the PixMapHandle
|
|
MOVE.L (A0), A1 ;and get the real ptr to pixmap
|
|
@2
|
|
CMP.W #1, pmPixelSize(A1) ;is it 1 bit per pixel deep?
|
|
BEQ.S @1 ;if yes, we're fine
|
|
MOVE.W #pixmapTooDeepErr, D0 ;return an error otherwise
|
|
BRA BMRBadEmpty ;clean up and bail out
|
|
@1
|
|
MOVE.W rowBytes(A1), rowNumBytes(A6) ;get the rowbytes from the bit/pixmap
|
|
ANDI.W #$7FFF, rowNumBytes(A6) ;mask off pixmap flag
|
|
MOVE.L bounds+topLeft(A1),D2 ;get topLeft
|
|
MOVE.W bounds+right(A1),D0 ;get right
|
|
|
|
;figure the number of longs per row (according to width, not rowbytes)
|
|
;so we can get a scanline buffer
|
|
SUB.W D2,D0 ;right - left
|
|
BLE BMREmptyOut ;if empty rect. then empty region
|
|
EXT.L D0
|
|
MOVE.L D0,D4
|
|
ADD.L D4,D4 ;double width for 2 bytes/ip
|
|
ADDQ.L #4+2,D4 ;add 4 bytes for y value and $7FFF word
|
|
;add 2 more for the $7FFF if the last line
|
|
ADD.L D4,D4 ;double, just 'cause I feel like it!
|
|
MOVE.L D4,max2Add(A6) ;save max. bytes for a given line
|
|
|
|
MOVEQ #32,D7 ;(side effect: clear high word of D7)
|
|
DIVU D7,D0 ;number of longs = width/32
|
|
|
|
;get a mask for the rightmost long into rightMask
|
|
MOVE.L D0,D3 ;save remainder(hi word)
|
|
SWAP D3 ;get remainder from width/32
|
|
MOVEQ #-1,D1 ;default rightmost long mask
|
|
TST.W D3 ;zero remainder?
|
|
BEQ.S @0 ;yes, $FFFF is a good mask
|
|
ADDQ.W #1,D0 ;we need one more long
|
|
SUB.W D3,D7 ;32 - remainder = zero bits to shift in
|
|
ASL.L D7,D1 ;get proper mask
|
|
@0 MOVE.L D1,rightMask(A6)
|
|
EXT.L D0
|
|
MOVE.L D0,rowLongs(A6) ;save # of longs
|
|
ASL.L #2,D0 ;longs => bytes
|
|
|
|
;get the scanline buffer (D0 = number of bytes per line)
|
|
_NewHandle clear ;get a scanline buffer (of zeroes)
|
|
BNE BMRBadEmpty ;if we failed then return a NIL handle
|
|
|
|
MOVE.L A0,slHandle(A6) ;save buffer handle
|
|
|
|
;figure the number of lines
|
|
MOVE.L D2,D3
|
|
SWAP D3 ;get top
|
|
MOVE.W bounds+bottom(A1),D0 ;get bottom
|
|
SUB.W D3,D0 ;bottom - top
|
|
BLE BMREmptyOut ;if empty rect. then empty region
|
|
|
|
MOVE.W D0,numLines(A6) ;number of lines
|
|
MOVE.L baseAddr(A1),A4 ;point to start of map
|
|
MOVE.W #rgnData,D7 ;initial region size
|
|
|
|
;OK, now we start the loops.
|
|
; A1 will point to the bitmap long,
|
|
; A2 to the region.
|
|
; A3 points to the current scanline buffer long.
|
|
; A4 will point to the row in the map.
|
|
; A5 points to the current word (= size + A2)
|
|
; D1 holds the current long (modified).
|
|
; D2 holds the leftmost coordinate of bitmap.bounds.
|
|
; D3 has the y coordinate, and
|
|
; D4 the x coordinate (high word stays clear!).
|
|
; D5 has number of longs remaining for current line.
|
|
; D6 holds the (on or off) value of the "beam" (for the line).
|
|
; D7 holds the size outside the longword loop (used as scratch while nibbling).
|
|
; (we assume at the very end that D7's high word has remained clear)
|
|
|
|
BMRHScramLine
|
|
MOVE.L regionH(A6),A2
|
|
MOVE.L (A2),A2 ;point to start of region
|
|
|
|
BMRLineLoop
|
|
LEA (A2,D7.W),A5 ;point to new region start + size
|
|
|
|
MOVE.L handSize(A6),D1 ;get handle size
|
|
SUB.W D7,D1 ;handle size - region size
|
|
CMP.L max2Add(A6),D1 ;is there enough for worst case on next line?
|
|
BGE.S @1 ;skippy if so
|
|
|
|
MOVE.L handSize(A6),D0 ;get handle size
|
|
ADD.L max2Add(A6),D0 ;add more than enough for worst case on next line
|
|
MOVE.L D0,handSize(A6) ;save new size
|
|
MOVE.L regionH(A6),A0 ;region handle
|
|
_SetHandleSize
|
|
BNE BMRBadEmpty ;if we failed then return a NIL handle
|
|
BRA.S BMRHScramLine ;rederef. handle and recompute current pointer
|
|
@1
|
|
|
|
MOVE.W D2,D4 ;get current x coordinate from left
|
|
MOVEQ #0,D6 ;beam initially off
|
|
MOVE.L A4,A1 ;start of current line into map pointer
|
|
MOVE.L rowLongs(A6),D5 ;longs remaining for current line
|
|
MOVE.L slHandle(A6),A3 ;A3 points to the current "differences" long
|
|
MOVE.L (A3),A3
|
|
|
|
; Note: within this loop we assume that nothing will be done to move the heap
|
|
|
|
MOVE.W D3,D0 ;get y position
|
|
BSR OutputRgnWord ;output y pos to region
|
|
|
|
MOVE.W D7,startSize(A6) ;save size at line start (a la Derwood)
|
|
BRA NextBMRLong ;enter the long loop
|
|
|
|
BMRLongLoop
|
|
MOVE.L (A1)+,D0 ;fetch the next long for this line
|
|
BMRLastLEntry
|
|
MOVE.L (A3),D1 ;get differences long
|
|
|
|
EOR.L D0,D1 ;compute the differences
|
|
BNE BMRDiff ;if not the same, skip ahead
|
|
|
|
BMRSame
|
|
;since we want to skip this long (it matches the previous line) we need to
|
|
;put out an ip if the beam is on
|
|
TST.B D6 ;beam on?
|
|
BEQ.S @1 ;skip if not
|
|
MOVE.W D4,(A5)+ ;pump it out
|
|
MOVEQ #0,D6 ;beam off
|
|
|
|
@1
|
|
ADD.W #32,D4 ;slip to next long's x coordinate
|
|
@2 ADDQ.W #4,A3 ;to next changes buffer long
|
|
BRA NextBMRLong
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
; Start of State Machine
|
|
|
|
; Handle state 0001
|
|
|
|
BMRState1
|
|
ADDQ.W #3,D4 ;bump x by 3
|
|
State1Common
|
|
MOVE.W D4,(A5)+ ;generate one
|
|
;Tog1StateDone
|
|
ADDQ.W #1,D4 ;bump x by one more
|
|
TogStateDone
|
|
NOT.B D6 ;toggle state
|
|
RTS
|
|
|
|
; Handle state 0010
|
|
|
|
BMRState2
|
|
ADDQ.W #2,D4 ;bump x by 2
|
|
MOVE.W D4,(A5)+ ;generate one
|
|
Gen1BumpBy1
|
|
BSR.S Gen1InvPoint ;and another one
|
|
BumpBy1
|
|
ADDQ.W #1,D4 ;bump once more
|
|
RTS ;state doesn't change
|
|
|
|
; Handle state 0011
|
|
|
|
BMRState3
|
|
ADDQ.W #2,D4 ;bump x by 2
|
|
MOVE.W D4,(A5)+ ;generate one
|
|
ADDQ.W #2,D4 ;bump
|
|
BRA.S TogStateDone ;toggle the state
|
|
|
|
; Handle state 0100
|
|
|
|
BMRState4
|
|
BSR.S Gen1InvPoint
|
|
BSR.S Gen1InvPoint
|
|
BumpBy2
|
|
ADDQ.W #2,D4
|
|
RTS
|
|
|
|
; Handle state 0101
|
|
|
|
BMRState5
|
|
BSR.S BMRState4 ;start out as state 4
|
|
SUBQ #1,D4
|
|
BRA.S State1Common ;use common code
|
|
|
|
; Handle state 0110
|
|
|
|
BMRState6
|
|
BSR.S Gen1InvPoint
|
|
ADDQ.W #1,D4
|
|
BRA.S Gen1BumpBy1
|
|
|
|
; Handle state 0111
|
|
|
|
BMRState7
|
|
BSR.S Gen1InvPoint
|
|
ADDQ.W #3,D4
|
|
BRA.S TogStateDone
|
|
|
|
; Gen1InvPoint bumps x by one and then generates a horizontal inversion point
|
|
|
|
Gen1InvPoint
|
|
ADDQ.W #1,D4 ;bump by 1, first
|
|
MOVE.W D4,(A5)+ ;add x value (ip) to region
|
|
RTS
|
|
|
|
; Handle State 1000
|
|
|
|
BMRState8
|
|
MOVE.W D4,(A5)+
|
|
BSR.S Gen1InvPoint
|
|
ADDQ.W #3,D4
|
|
RTS
|
|
|
|
; Handle State 1001
|
|
|
|
BMRState9
|
|
MOVE.W D4,(A5)+
|
|
BSR.S Gen1InvPoint
|
|
ADDQ.W #2,D4
|
|
BRA.S State1Common
|
|
|
|
; Handle State 1010 (most complicated case)
|
|
|
|
BMRState10
|
|
MOVE.W D4,(A5)+
|
|
BSR.S Gen1InvPoint
|
|
BSR.S Gen1InvPoint
|
|
BRA.S Gen1BumpBy1
|
|
|
|
; Handle State 1011
|
|
|
|
BMRState11
|
|
MOVE.W D4,(A5)+
|
|
BSR.S Gen1InvPoint
|
|
BSR.S Gen1InvPoint
|
|
ADDQ.W #2,D4
|
|
BRA.S TogStateDone
|
|
|
|
; Handle State 1100
|
|
|
|
BMRState12
|
|
MOVE.W D4,(A5)+
|
|
ADDQ.W #2,D4
|
|
MOVE.W D4,(A5)+
|
|
BRA.S BumpBy2
|
|
|
|
; Handle State 1101
|
|
|
|
BMRState13
|
|
BSR.S BMRState12
|
|
SUBQ #1,D4
|
|
BRA.S State1Common
|
|
|
|
; Handle State 1110
|
|
|
|
BMRState14
|
|
MOVE.W D4,(A5)+
|
|
ADDQ.W #3,D4
|
|
MOVE.W D4,(A5)+
|
|
BRA.S BumpBy1
|
|
|
|
; State table
|
|
|
|
BMRHandler
|
|
BRA.S BMRState0
|
|
BRA.S BMRState1
|
|
BRA.S BMRState2
|
|
BRA.S BMRState3
|
|
|
|
BRA.S BMRState4
|
|
BRA.S BMRState5
|
|
BRA.S BMRState6
|
|
BRA.S BMRState7
|
|
|
|
BRA.S BMRState8
|
|
BRA.S BMRState9
|
|
BRA.S BMRState10
|
|
BRA.S BMRState11
|
|
|
|
BRA.S BMRState12
|
|
BRA.S BMRState13
|
|
BRA.S BMRState14
|
|
|
|
; Handle State 15 or 1111
|
|
|
|
BMRState15
|
|
MOVE.W D4,(A5)+ ;generate one now
|
|
NOT.B D6 ;toggle the state
|
|
|
|
; Handle State 0 or 0000
|
|
|
|
BMRState0
|
|
ADDQ.W #4,D4
|
|
RTS
|
|
|
|
; End of the State Guys
|
|
|
|
;----------------------------------------------------------------------------------------
|
|
|
|
BMRDiff
|
|
MOVE.L D0,(A3)+ ;fix up scanline buffer for next time
|
|
|
|
; this long is different from the last one, so output a bunch
|
|
; of inversion points by pumping it through the state machine, a nibble
|
|
; at a time.
|
|
|
|
MOVEQ #3,D7 ;4 bytes to process (D7 high word clear)
|
|
MOVEQ #0,D0 ;prevent need to mask for first nibble
|
|
|
|
; here is the loop where we feed it through a nibble at a time.
|
|
; it's worth it to special case a whole byte of 0
|
|
|
|
BMRByteLoop
|
|
ROL.L #8,D1 ;get next (topmost) byte
|
|
TST.B D1 ;is it zero?
|
|
BNE.S BMRNibble ;if not, 4 bits at a time
|
|
|
|
TST.B D6
|
|
BNE.S BMRNibble ;if beam on, must pass through
|
|
|
|
;the top 8 are zero, so we can save some time
|
|
|
|
ADDQ.W #8,D4 ;bump x
|
|
BRA.S BMRNextByte
|
|
|
|
;take care of the rightmost long for a line
|
|
|
|
BMRLastLong
|
|
MOVE.L (A1),D0 ;fetch the long from the bitmap
|
|
AND.L rightMask(A6),D0 ;mask off right bits that aren't in map
|
|
BRA BMRLastLEntry ;go process this long
|
|
|
|
; handle the first nibble
|
|
|
|
BMRNibble
|
|
MOVE.B D1,D0 ;get byte
|
|
EOR.B D6,D0 ;invert nibble when beam is on
|
|
LSR.B #4,D0 ;get 1st nibble
|
|
ADD.W D0,D0 ;double for word index
|
|
|
|
JSR BMRHandler(D0.W) ;invoke the handler
|
|
|
|
; handle the second nibble
|
|
|
|
MOVE.B D1,D0 ;get byte again
|
|
EOR.B D6,D0 ;invert nibble when beam is on
|
|
AND.W #%1111,D0 ;mask to it
|
|
ADD.W D0,D0 ;double for word index
|
|
|
|
JSR BMRHandler(D0.W) ;invoke the handler
|
|
|
|
BMRNextByte
|
|
DBRA D7,BMRByteLoop ;loop for all 8 nibbles
|
|
|
|
; bump to the next long
|
|
|
|
NextBMRLong
|
|
SUBQ.W #1,D5 ;decrement longword index
|
|
BGT BMRLongLoop ;not at end, loop for whole line
|
|
BEQ.S BMRLastLong ;process last long for this line
|
|
|
|
; we've reached the end of the (this) line
|
|
BMREOL
|
|
MOVE.W A5,D7 ;current region pointer
|
|
SUB.W A2,D7 ;figga region size
|
|
CMP.W startSize(A6),D7 ;did we add inv. pts to this line?
|
|
BEQ.S BMRNoLine ;br = no, so back up
|
|
BLT BMR32KErr ;if the size decreased, we overflowed
|
|
|
|
; if the state is on, generate one last inversion point
|
|
|
|
TST.B D6
|
|
BEQ.S @1
|
|
|
|
MOVE.W D4,(A5)+ ;generate a last one
|
|
ADDQ.W #2,D7 ;keep sizable advantage
|
|
@1
|
|
|
|
; end the scan line with the traditional $7FFF
|
|
|
|
BSR.S OutputLastRgnWord
|
|
|
|
BMREOL2
|
|
ADDQ.W #1,D3 ;bump y position
|
|
MOVE.W D2,D4 ;start x at left again
|
|
ADD.W rowNumBytes(A6),A4 ;bump to next row in map
|
|
SUBQ.W #1,numLines(A6)
|
|
BGT BMRLineLoop ;if we're not done then do next line
|
|
BLT.S BMRFinis ;br if really done
|
|
|
|
; as the last line process an imaginary line of zeroes to end the regionÉ
|
|
MOVE.L rowLongs(A6),D0
|
|
ASL.L #2,D0 ;longs => bytes
|
|
_NewHandle clear ;get a full line of zero bits
|
|
BNE BMRBadEmpty ;if we failed then return a NIL handle <SM2> CSS
|
|
MOVE.L A0,lastLineH(A6) ;save handle
|
|
MOVE.L (A0),A4 ;start of current line
|
|
BRA BMRHScramLine ;do this last one (and rederef handle)
|
|
|
|
BMRNoLine
|
|
SUBQ.L #2,A5 ;back up pointer
|
|
SUBQ.W #2,D7 ;back down size
|
|
BRA.S BMREOL2 ;go for next line
|
|
|
|
; Append the "end of line" token to the region
|
|
|
|
OutputLastRgnWord
|
|
MOVE.W #$7FFF,D0
|
|
|
|
; OutputRgnWord takes the word in D0, appends it to the region,
|
|
; and leaves the condition codes set for ADDQ.W D7 (which contains the length)
|
|
|
|
OutputRgnWord
|
|
MOVE.W D0,(A5)+ ;put a word to the region
|
|
ADDQ.W #2,D7 ;ink the size
|
|
RTS
|
|
|
|
|
|
; all done so clean up, output the final $7FFF
|
|
BMRFinis
|
|
MOVE.L lastLineH(A6),A0
|
|
SafeDisposeHandle ;get rid of that last line of zeroes
|
|
|
|
CMP.W #10,D7 ;is region empty of inversion points?
|
|
BEQ.S BMREmptyOut ;skip if so (it's an empty region)
|
|
|
|
BSR.S OutputLastRgnWord ;put End-O-Region ($7FFF) word
|
|
BMI.S BMR32KErr ;if we went negative, we overflowed!
|
|
|
|
; find the smallest rectangle that encompasses all the inversion points
|
|
; A0 will point to the current region word, A1 to the start of the line
|
|
; D1 will have the smallest x, D2 the largest x, D4 will contain $7FFF
|
|
; D3 gets the smallest y value (which we know at the start)
|
|
|
|
LEA rgnData(A2),A0 ;point A0 past the rgnBBox
|
|
MOVE.W #$7FFF,D4
|
|
MOVE.W D4,D1 ;smallest x so far = $7FFF
|
|
MOVE.W #$8000,D2 ;largest x so far = -32768
|
|
MOVE.W (A0),D3 ;smallest y there is
|
|
BRA.S BMRPackStart ;enter loop
|
|
|
|
BMRPackY
|
|
MOVE.L A0,A1 ;remember where the y value is (sort of)
|
|
|
|
CMP.W (A0)+,D1 ;less than smallest x so far?
|
|
BLE.S @1 ;skip if not
|
|
MOVE.W -2(A0),D1 ;new smallest x
|
|
|
|
@1 CMP.W (A0)+,D4 ;end of line?
|
|
BNE.S @1 ;if not then keep looking
|
|
|
|
CMP.W -4(A0),D2 ;last x greater than largest x so far?
|
|
BGE.S BMRPackStart ;skip if not
|
|
MOVE.W -4(A0),D2 ;new largest x
|
|
|
|
BMRPackStart
|
|
MOVE.W (A0)+,D0 ;get next word (y value or $7FFF)
|
|
CMP.W D4,D0 ;if $7FFF then we're done
|
|
BNE.S BMRPackY ;otherwise loop
|
|
|
|
SWAP D3 ;top into top word
|
|
MOVE.W D1,D3 ;left into bottom word
|
|
MOVE.W -2(A1),D4 ;bottom (from last y at start of line)
|
|
SWAP D4 ;move bottom to high word
|
|
MOVE.W D2,D4 ;get right
|
|
|
|
CMP.W #28,D7 ;size = 28? (do we have a rect. region?)
|
|
BEQ.S BMRRect ;skip if so
|
|
|
|
BRA.S BMROut ;return complex region
|
|
|
|
;the region would exceed 32K, so we have to error out, man
|
|
BMR32KErr
|
|
MOVE.W #rgnTooBigErr,D0 ;if >32K needed return error
|
|
|
|
;we come here after failing a SetHandleSize (or NewHandle)
|
|
BMRBadEmpty
|
|
MOVE.W D0,result(A6) ;OSErr function result
|
|
|
|
; emptify the region on errors (or when it should be empty with no error)
|
|
BMREmptyOut
|
|
MOVE.L regionH(A6),A0 ;handle to region
|
|
MOVE.L (A0),A2 ;point to it
|
|
CLR.L D3 ;(0, 0) to topLeft
|
|
CLR.L D4 ;(0, 0) to botRight
|
|
|
|
BMRRect
|
|
MOVEQ #10,D7 ;the size of the region = 10
|
|
|
|
;output the region with size (longword, high word clear) in D7
|
|
;D3 comes in with topLeft, D4 with botRight
|
|
BMROut
|
|
MOVE.W D7,(A2)+ ;the size of the region
|
|
MOVE.L D3,(A2)+ ;topLeft to rgnBBox
|
|
MOVE.L D4,(A2) ;botRight to rgnBBox
|
|
MOVE.L D7,D0 ;size
|
|
MOVE.L regionH(A6),A0 ;handle to region
|
|
_SetHandleSize
|
|
|
|
BMRDspSL
|
|
MOVE.L slHandle(A6),A0
|
|
SafeDisposeHandle ;get rid of the scanline buffer (even if NIL)
|
|
|
|
BMRDone
|
|
MOVEM.L (SP)+,A2-A5/D3-D7 ;restore work registers
|
|
UNLK A6
|
|
MOVE.L (SP)+,A0 ;pop return address
|
|
ADD #paramSize,SP ;pop params
|
|
JMP (A0)
|
|
ENDWITH
|
|
|
|
|
|
END
|