mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-26 01:49:19 +00:00
351 lines
14 KiB
Plaintext
351 lines
14 KiB
Plaintext
;
|
||
; File: DeviceLoop.a
|
||
;
|
||
; Contains: _DeviceLoop, a trap to assist in multi-device drawing
|
||
;
|
||
; Written by: Chris Derossi
|
||
;
|
||
; Copyright: © 1990-1991 by Apple Computer, Inc., all rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <8> 1/13/92 PN Adding the quick draw "DeviceLoop" into ROM
|
||
; <7> 3/26/91 dba csd: take out VisRgnChanged, since I didn’t really understand
|
||
; <6> 9/14/90 csd Used the interfaces instead of local definitions.
|
||
; <5> 8/20/90 dba call VisRgnChanged, now that it exists
|
||
; <4> 7/16/90 DC Fixed bug which I so graciously introduced into this code with
|
||
; change <3> Used d0 to hold first GDevice to check in stead of
|
||
; A4.
|
||
; <3> 7/12/90 DC changed loop priming to use TheGDevice instead of DeviceList
|
||
; whe TheGDevice is not equal to MainDevice (off-screen case)
|
||
; <2> 4/11/90 dba put in the trap number
|
||
; <1> 4/11/90 dba made it a linked patch
|
||
;
|
||
|
||
print push,off
|
||
load 'StandardEqu.d'
|
||
include 'LinkedPatchMacros.a'
|
||
print pop
|
||
|
||
;----------------------------------------------------------------------------------------------
|
||
; PROCEDURE DeviceLoop(drawingRgn : RgnHandle; drawingProc : ProcPtr;
|
||
; userData : LongInt; flags : DeviceLoopFlags);
|
||
;----------------------------------------------------------------------------------------------
|
||
; When DeviceLoop gets called, it searches all the active screen devices for the
|
||
; ones that intersect the drawingRgn. The drawingRgn is in local coordinates, and
|
||
; will usually be a port’s visRgn (after a BeginUpdate call). For each device which
|
||
; intersects drawingRgn, the drawingProc routine is called. When the drawingProc is called,
|
||
; the current port’s visRgn will be the intersection of the original visRgn and the
|
||
; intersecting portions of the device.
|
||
; The drawingProc should be declared as follows:
|
||
;
|
||
; PROCEDURE DrawingProc(depth : Integer; deviceFlags : Integer; targetDevice : GDHandle;
|
||
; userData : LongInt);
|
||
;
|
||
; where depth will be the pixelSize of the device, and flags are the gdFlags from
|
||
; the GDevice. The userData passed to DeviceLoop is also passed to the drawingProc.
|
||
;
|
||
; When called from a machine without Color QuickDraw, the targetDevice parameter passed to the
|
||
; drawing proc is set to NIL.
|
||
;
|
||
; The following flags may be passed to DeviceLoop:
|
||
;
|
||
; singleDevices If this flag is set, then similar devices are not grouped together when the
|
||
; drawingProc is called. If this flag is not set, DeviceLoop will only call
|
||
; the drawingProc once for each set of similar devices, but only the first
|
||
; one found is passed as targetDevice. It is assumed to be representative of
|
||
; all the similar devices.
|
||
; dontMatchSeeds If this flag is set, then color table seeds are not considered significant
|
||
; when comparing devices for similarity. Device similarity is based on color
|
||
; table depth and important gdevice flags (at this time, only the
|
||
; monochrome/color flag is considered important). This flag is ignored if
|
||
; the singleDevices flag is set.
|
||
; allDevices When this flag is set, the drawingRgn is ignored and DeviceLoop will call
|
||
; the drawingProc for all active screen gdevices. Whether or not similar
|
||
; devices are grouped together for a single call to the drawingProc depends
|
||
; on the setting of the singleDevices flag. The current port’s visRgn is not
|
||
; affected when this flag is set.
|
||
;----------------------------------------------------------------------------------------------
|
||
; Register Use:
|
||
; D3 current device’s ordinal number for indexing into finished bitmap
|
||
; D4 RgnHandle for working region
|
||
; D5 bitmap of devices we’ve done
|
||
; D6 depth of current device (high word) & flags of current device (low word)
|
||
; D7 ctSeed of current device
|
||
; A2 current port
|
||
; A3 pointer to current device
|
||
; A4 handle to current device
|
||
;----------------------------------------------------------------------------------------------
|
||
|
||
|
||
DeviceLoop patchproc _DeviceLoop,(Plus,SE,II,Portable,IIci)
|
||
|
||
activeScreenMask EQU $A000
|
||
importantFlagsMask EQU $A001
|
||
fakeDeviceFlags EQU $A801
|
||
|
||
DeviceLoopFrame RECORD {A6Link},DECR
|
||
StartParams EQU *
|
||
drawingRgn DS.L 1
|
||
drawingProc DS.L 1
|
||
userData DS.L 1
|
||
flags DS.L 1
|
||
ParamSize EQU StartParams-*
|
||
Return DS.L 1
|
||
A6Link DS.L 1
|
||
savedVis DS.L 1
|
||
localRect DS.W 4
|
||
callerRegs DS.L 8
|
||
visAndDrawRgn DS.L 1
|
||
LocalSize EQU *
|
||
ENDR
|
||
|
||
with DeviceLoopFrame
|
||
|
||
link A6, #LocalSize
|
||
movem.l D3-D7/A2-A4, callerRegs(A6) ; save the callers registers
|
||
|
||
btst #6, ROM85 ; Color QuickDraw available?
|
||
bnz @classicQD ; if not, handle old case
|
||
|
||
move.l TheGDevice, D0 ; Get the handle to the current GDevice
|
||
move.l MainDevice, D1 ; Get the handle to the main device
|
||
cmp.l D0, D1 ; if the two are not equal…
|
||
bne.s @checkForOne ; we use TheGDevice to prime our device loop
|
||
move.l DeviceList, D0 ; otherwise, we use DeviceList
|
||
|
||
@checkForOne
|
||
movea.l D0, A0 ; D0 here contains the first GDevice of the list we will use.
|
||
move.l (A0), A0
|
||
tst.l gdNextGD(A0) ; is there a second device?
|
||
beq @oneDevice ; if not, quick exit
|
||
|
||
move.l D0, A4 ; put the beginning of the device list we are using in A4
|
||
move.l (A5), A2 ; point to QD globals
|
||
move.l thePort(A2), A2 ; point to current port
|
||
move.l flags(A6), D0 ; what are the current options?
|
||
btst #allDevicesBit, D0 ; are we ignoring drawingRgn?
|
||
bnz.s @regionsReady ; if so, there’s no region work
|
||
|
||
move.l visRgn(A2), savedVis(A6) ; save the untouched visRgn
|
||
subq #4, SP ; room for region handle
|
||
_NewRgn
|
||
move.l (SP)+, visRgn(A2) ; new working visRgn
|
||
subq #4, SP ; room for region handle
|
||
_NewRgn
|
||
move.l (SP)+, D4 ; new device rect region
|
||
move.l savedVis(A6), -(SP) ; current real visRgn
|
||
move.l drawingRgn(A6), -(SP) ; caller’s drawing region
|
||
subq #4, SP ; room for region handle
|
||
_NewRgn
|
||
move.l (SP), visAndDrawRgn(A6) ; for intersection of vis and drawing regions
|
||
_SectRgn ; calculate clipped drawing region
|
||
@regionsReady
|
||
|
||
moveq #0, D5 ; clear finished bitmap
|
||
moveq #0, D3 ; we’re starting with device 0
|
||
@deviceIntersect
|
||
move.l A4, D0 ; is the GDHandle NIL?
|
||
beq @noMore ; if so, no more devices
|
||
move.l (A4), A3 ; point at the GDevice record
|
||
bsr TestAndIntersect ; is device good for drawing?
|
||
bz.s @nextDevice ; if not, keep searching
|
||
|
||
move.l flags(A6), D0 ; get the caller’s options
|
||
btst #allDevicesBit, D0 ; are we ignoring regions?
|
||
bnz.s @visRgnSetup ; if so, don’t change the visRgn
|
||
|
||
move.l D4, -(SP) ; rectangle region handle
|
||
pea localRect(A6) ; this device (local coords)
|
||
_RectRgn ; region = device rect (local)
|
||
move.l D4, -(SP) ; device rect region (local)
|
||
move.l visAndDrawRgn(A6), -(SP) ; ANDed with clipped drawing region
|
||
move.l visRgn(A2), -(SP) ; turns into port’s visRgn
|
||
_SectRgn
|
||
move.l (A4), A3 ; fix GDevicePtr
|
||
@visRgnSetup
|
||
|
||
move.l gdPMap(A3), A0 ; device’s PixMapHandle
|
||
move.l (A0), A0 ; device’s PixMapPtr
|
||
move.w pmPixelSize(A0), D6 ; device’s depth
|
||
swap D6 ; put depth high
|
||
move.w gdFlags(A3), D6 ; get device flags in low word
|
||
move.l pmTable(A0), A0 ; device’s color table handle
|
||
move.l (A0), A0
|
||
move.l ctSeed(A0), D7 ; stash device’s ctab seed
|
||
move.l flags(A6), D0 ; get caller’s flags
|
||
btst #singleDevicesBit, D0 ; should we group devices?
|
||
bnz.s @groupingDone ; if not, don’t call AddSimilar
|
||
bsr AddSimilarDevices ; find all the like devices
|
||
@groupingDone
|
||
movem.l D3-D7/A2-A4/A6, -(SP) ; save OUR registers
|
||
swap D6
|
||
move.l D6, -(SP) ; pass depth and flags
|
||
move.l A4, -(SP) ; and the GDHandle
|
||
move.l userData(A6), -(SP) ; and finally the user’s long
|
||
move.l drawingProc(A6), A0 ; pointer to drawing procedure
|
||
movem.l callerRegs(A6), D3-D7/A2-A4 ; restore caller’s registers
|
||
move.l A6Link(A6), A6 ; and restore caller’s A6
|
||
jsr (A0) ; call the drawing procedure
|
||
movem.l (SP)+, D3-D7/A2-A4/A6 ; get OUR register set back
|
||
move.l (A4), A3 ; fix GDevicePtr
|
||
@nextDevice
|
||
move.l gdNextGD(A3), A4 ; get next device in chain
|
||
addq #1, D3 ; increment device number
|
||
bra.s @deviceIntersect ; try this one
|
||
|
||
@classicQD
|
||
move.l A6, -(SP) ; save our stack frame ptr
|
||
move.w #1, -(SP) ; pass depth (always 1)
|
||
move.w #fakeDeviceFlags, -(SP) ; and gdflags (something reasonable)
|
||
clr.l -(SP) ; NIL for GDHandle
|
||
bra.s @simpleDeviceCommon
|
||
|
||
@oneDevice
|
||
move.l A6, -(SP) ; save our stack frame ptr
|
||
move.l gdPMap(A0), A1 ; PixMapHandle
|
||
move.l (A1), A1 ; PixMapPtr
|
||
move.w pmPixelSize(A1), -(SP) ; pass depth
|
||
move.w gdFlags(A0), -(SP) ; and gdflags
|
||
move.l D0, -(SP) ; and the GDHandle
|
||
|
||
@simpleDeviceCommon
|
||
move.l userData(A6), -(SP) ; and the user’s long
|
||
move.l drawingProc(A6), A0 ; the procedure’s address
|
||
move.l A6Link(A6), A6 ; and restore caller’s A6
|
||
jsr (A0) ; call the drawing code
|
||
move.l (SP)+, A6 ; restore access to our stack frame
|
||
bra.s @exit
|
||
|
||
@noMore
|
||
move.l flags(A6), D0 ; what are the current options?
|
||
btst #allDevicesBit, D0 ; are we ignoring drawingRgn?
|
||
bnz.s @exit ; if so, no regions to clean up
|
||
|
||
move.l visRgn(A2), -(SP) ; temp working visRgn
|
||
_DisposRgn
|
||
move.l visAndDrawRgn(A6), -(SP) ; temp clipped drawingRgn
|
||
_DisposRgn
|
||
move.l D4, -(SP) ; temp device rect rgn
|
||
_DisposRgn
|
||
move.l savedVis(A6), visRgn(A2) ; put original visRgn back
|
||
@exit
|
||
movem.l callerRegs(A6), D3-D7/A2-A4 ; restore regs
|
||
unlk A6
|
||
move.l (SP)+, A0 ; clean stack and return
|
||
lea ParamSize(SP), SP
|
||
jmp (A0)
|
||
|
||
|
||
AddSimilarDevices
|
||
; Starting with gdNextGD(A3), find all the devices that:
|
||
; have the same depth as D6 (high word)
|
||
; have the same important flags as D6 (low word)
|
||
; optionally have the same ctSeed as D7
|
||
; haven’t yet been drawn to
|
||
; are active screens (automatic because the flag bit for active is in importantFlagsMask)
|
||
; intersect drawingRgn(A6)
|
||
;
|
||
; When such a device is found, do:
|
||
; visRgn(A2) := visRgn(A2) | (gdRect & clipped drawingRgn)
|
||
; mark doneDevices bitmap (D5.L) so we don’t do this one again
|
||
|
||
movem.l A3-A4/D3/D6, -(SP) ; save original state
|
||
andi.w #importantFlagsMask, D6 ; keep only pertinent flags
|
||
move.l gdNextGD(A3), A4 ; start with next device
|
||
addq #1, D3 ; which is next in number, too
|
||
@addLoop
|
||
move.l A4, D0 ; is there a GDHandle?
|
||
bz.s @noMore ; if NIL, then we’re done
|
||
|
||
move.l (A4), A3 ; handle->ptr
|
||
bsr.s TestAndIntersect ; see if device is okay by itself
|
||
bz.s @nextDevice ; if not, try next one
|
||
|
||
move.w gdFlags(A3), D0 ; get device attributes
|
||
andi.w #importantFlagsMask, D0 ; strip unimportant ones
|
||
cmp.w D0, D6 ; is this device similar to test device?
|
||
bne.s @nextDevice ; if not, don’t use it
|
||
|
||
move.l gdPMap(A3), A0 ; get device’s PixMapHandle
|
||
move.l (A0), A0 ; get device’s PixMapPtr
|
||
move.l D6, D0 ; get depth and flags
|
||
swap D0 ; get depth into low word
|
||
cmp.w pmPixelSize(A0), D0 ; save depth as test device?
|
||
bne.s @nextDevice ; if not, don’t use it
|
||
|
||
move.l flags(A6), D0 ; get the option flags
|
||
btst #dontMatchSeedsBit, D0 ; should we check ctSeeds?
|
||
bnz.s @seedsChecked ; if not, skip this next check
|
||
move.l pmTable(A0), A0 ; handle to color table
|
||
move.l (A0), A0
|
||
cmp.l ctSeed(A0), D7 ; are the seeds the same?
|
||
bne.s @nextDevice ; if not, don’t use this one
|
||
@seedsChecked
|
||
|
||
move.l flags(A6), D0 ; what are the current options?
|
||
btst #allDevicesBit, D0 ; are we ignoring drawingRgn?
|
||
bnz.s @visRgnSetup ; if so, no regions to setup
|
||
|
||
move.l D4, -(SP) ; rectangle region handle
|
||
pea localRect(A6) ; this device (local coords)
|
||
_RectRgn ; region = device rect (local)
|
||
move.l D4, -(SP) ; device rect region (local)
|
||
move.l visAndDrawRgn(A6), -(SP) ; ANDed with clipped drawing region
|
||
move.l D4, -(SP) ; turns into intersected rect region
|
||
_SectRgn
|
||
move.l D4, -(SP) ; intersected device rect region
|
||
move.l visRgn(A2), -(SP) ; and previously setup visRgn
|
||
move.l (SP), -(SP) ; get ORed together
|
||
_XorRgn ; XOr is a fast way to Union when guaranteed no overlap
|
||
move.l (A4), A3 ; fix GDevicePtr
|
||
|
||
@visRgnSetup
|
||
bset.l D3, D5 ; mark this device done
|
||
@nextDevice
|
||
move.l gdNextGD(A3), A4 ; get next device in chain
|
||
addq #1, D3 ; increment device number
|
||
bra.s @addLoop ; try this one
|
||
@noMore
|
||
movem.l (SP)+, A3-A4/D3/D6 ; restore caller’s state
|
||
rts
|
||
|
||
|
||
TestAndIntersect
|
||
; Inputs:
|
||
; A3 device to test (dereferenced GDHandle)
|
||
; D3 this device’s ordinal number
|
||
; Outputs:
|
||
; CCs zero if not okay, non-zero if okay
|
||
; localRect(A6) is set to devices rectangle in local coordinates
|
||
|
||
btst.l D3, D5 ; this device already done?
|
||
bnz.s @fail ; if so, it’s not okay
|
||
move.w gdFlags(A3), D0 ; get this device’s flags
|
||
andi.w #activeScreenMask, D0 ; extract screen & active bits
|
||
cmpi.w #activeScreenMask, D0 ; are both bits set?
|
||
bne.s @fail ; if not, don’t use device
|
||
move.l gdRect(A3), localRect(A6) ; copy topLeft of device rect
|
||
move.l gdRect+4(A3), localRect+4(A6) ; and bottomRight
|
||
pea localRect(A6) ; push address of copied device rect
|
||
_GlobalToLocal ; and convert it to local coords.
|
||
pea localRect+bottom(A6) ; push address of copied device rect bottomRight
|
||
_GlobalToLocal ; and convert it to local coords.
|
||
|
||
move.l flags(A6), D0 ; get the options
|
||
btst #allDevicesBit, D0 ; should we accept all screens?
|
||
bnz.s @exit ; if set, exit with CCs non-zero
|
||
|
||
subq #2, SP ; room for boolean result
|
||
pea localRect(A6) ; local version of GDRect
|
||
move.l drawingRgn(A6), -(SP) ; region to test
|
||
_RectInRgn ; does device intersect region?
|
||
tst.b (SP)+ ; see if it does
|
||
bra.s @exit
|
||
@fail
|
||
moveq #0, D0
|
||
@exit
|
||
rts
|
||
|
||
END
|