mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-28 13:52:37 +00:00
2258 lines
84 KiB
Plaintext
2258 lines
84 KiB
Plaintext
;
|
||
; File: ClassicGWorld.a
|
||
;
|
||
; Contains: Classic QuickDraw version of off-screen code
|
||
;
|
||
; Copyright: © 1989-1990 by Apple Computer, Inc., all rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <19> 2/13/91 KON JDR, BRC #NONE: There was an MPW error message in the middle of
|
||
; this file on the last check in which broke the build. Sorry.
|
||
; <18> 2/13/91 KON CEL: BRC# unknown: UpdateGWorld does not return reallocPix flag
|
||
; when clipPix and stretchPix were set.
|
||
; <17> 2/11/91 KON CEL: BRC# 82568: Fix bug when Update GWorld crashes when
|
||
; shrinking the buffer. Also, BRC# 82630: UpdateGWorld crashed
|
||
; when buffer purged. This was a problem in NewGWorld.
|
||
; <16> 1/15/91 KON Change useMFTempBit to useTempMemBit. [csd]
|
||
; <15> 9/25/90 KON Change Offscreen Version to 130. Now all 7.0 offscreen versions
|
||
; return 130.
|
||
; <14> 9/16/90 KON Change black and white offscreen version to $30. Currently
|
||
; Gestalt returns 0 on B&W machines, while the color versions
|
||
; return offscreen version number +$100.
|
||
; <13> 9/15/90 gbm Fix bug where the bitmap bounds is incorrectly calculated for
|
||
; NewGWorld when the depth is non-zero.
|
||
; <12> 6/26/90 KON NewGWorld was trashing registers, NewTempScreenBuffer now checks
|
||
; for valid rects.
|
||
; <11> 6/25/90 KON Check if bounding rect is valid when calling NewGWorld.
|
||
; <10> 6/20/90 JSM Check for _OSDispatch correctly for the Mac Plus in
|
||
; NewHandleCommaTemp, convert boundRect to local coordinates in
|
||
; NewGWBuffer (Darin).
|
||
; <9> 6/19/90 JSM Make sure _OSDispatch is implemented in NewHandleCommaTemp
|
||
; before calling it.
|
||
; <8> 6/8/90 dba fix bug in buffer size for NewScreenBuffer case; must calculate
|
||
; buffer based on actual alignment since we don’t get the extra 31
|
||
; bits of slop
|
||
; <7> 4/26/90 csd link and save registers for NewScreenBuffer and
|
||
; NewTempScreenBuffer before trashing D5, D6, and D7 and falling
|
||
; into NewGWBuffer.
|
||
; <6> 4/11/90 dba fix bug where NewScreenBuffer doesn’t return an error code
|
||
; <5> 4/7/90 KON Fix bug in depth 0 gWorlds, fix disposing of gWorlds.
|
||
; <4> 4/4/90 KON get rid of short branches between modules (not supported by
|
||
; linked patches)
|
||
; <3> 3/16/90 KON Make it link, made it work for simple case.
|
||
; <2> 12/28/89 dba made it assemble; code is OK now, but lots of comments and
|
||
; random shit is left from when this was GWorld.a, and it has not
|
||
; been tested at all yet
|
||
; <1> 12/28/89 dba first checked in to BBS
|
||
; 12/28/89 dba created today (with BAL) from GWorld.a
|
||
;
|
||
; To Do:
|
||
; reduce the size by using registers
|
||
; UpdateGWorld is much too long and complex; a little thought will shorten it
|
||
;
|
||
|
||
OffscreenVersNum equ $130 ; B&W offscreen version for 7.0
|
||
|
||
;___________________________________________________________________________
|
||
|
||
; PixMaps in classic GWorlds have two possible version numbers
|
||
|
||
pmVersionLocked equ 1 ; marks that baseAddr is a clean derefed handle
|
||
pmVersionUnlocked equ 2 ; marks that baseAddr is a handle
|
||
|
||
pmVersionLockedBit equ 0 ; marks that baseAddr is a clean derefed handle
|
||
pmVersionHandleBit equ 1 ; marks that baseAddr is a handle
|
||
|
||
;___________________________________________________________________________
|
||
|
||
gwPortPixMap equ portRec ; PixMapHandle is just after the port
|
||
gwPortSize equ gwPortPixMap+4 ; total size
|
||
|
||
gwPMVersion equ bitMapRec ; version is just after the BitMap
|
||
gwPMPort equ gwPMVersion+2 ; port is just after the version
|
||
gwPMUseMFTemp equ gwPMPort+4 ; flag if we used temp. memory
|
||
gwPMSize equ gwPMUseMFTemp+2 ; total size
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Extensions to Quickdraw for 32-bit Quickdraw and Graphics Accelerators
|
||
;
|
||
; This file consists of:
|
||
;
|
||
; 1. Offscreen Graphics Environments
|
||
; NewGWorld: create an offscreen graphics world
|
||
; GetGWorld: get the current graphics world
|
||
; SetGWorld: set the current graphics world
|
||
; UpdateGWorld: adapt the graphics world to new depth, alignment, etc.
|
||
; DisposeGWorld: dispose of the graphics world
|
||
; LockPixels: lock the offscreen buffer (call before calling Quickdraw)
|
||
; UnlockPixels: unlock the offscreen buffer after drawing is finished
|
||
; AllowPurgePixels: make offscreen buffer purgeable
|
||
; NoPurgePixels: make offscreen buffer unpurgeable
|
||
; GetPixelsState: return the lock and purge state of the offscreen buffer
|
||
; SetPixelsState: set the lock and purge state of the offscreen buffer
|
||
; GetPixBaseAddr: waits until Async QD is done and return a 32-bit pointer to the offscreen buffer
|
||
; GetGWorldDevice: returns the attached device to an offscreen GWorld.
|
||
; NewScreenBuffer: allocates only an offscreen pixmap
|
||
; DisposeScreenBuffer: diposes of an offscreen pixmap.
|
||
;
|
||
; 2. Asynchronous Quickdraw
|
||
; PortChanged: notifies Quickdraw of any non-procedural changes to a port
|
||
; PixPatChanged: notifies Quickdraw of any non-procedural changes to a pixpat
|
||
; CTabChanged: notifies Quickdraw of any non-procedural changes to a color table
|
||
; GDeviceChanged: notifies Quickdraw of any non-procedural changes to a gDevice
|
||
;
|
||
; 3. Utilities
|
||
; GetMaxAreaDevice: find device with largest overlapping area with a given rectangle
|
||
; FindInverseTable: find an already built inverse table for a given color table in the device list
|
||
; QDDone: becomes true when the pending Quickdraw calls on a given port are completed
|
||
; BitMapDone: becomes true when the pending Quickdraw calls on a given pixmap are completed
|
||
;
|
||
;----------------------------------------------------------------------------
|
||
; THINGS TO DO:
|
||
;
|
||
; 1.Some of the same code is used in three different routines (NewGWorld, UpdateGWorld,
|
||
; and NewScreenBuffer). Rearchitect it to use subroutines.
|
||
;
|
||
; 2.Make GetMaxAreaDevice smarter and actually use it. GetMaxAreaDevice could estimate
|
||
; the break-even performance point between unaligned CopyBits and CopyBits
|
||
; with color mapping in terms of surface area and decide between which device
|
||
; to align the pixmap to.
|
||
;
|
||
;----------------------------------------------------------------------------
|
||
|
||
QDExtDispatcher PROC EXPORT
|
||
IMPORT NewGWorld, LockPixels, UnlockPixels, UpdateGWorld, DisposeGWorld
|
||
IMPORT GetGWorld, SetGWorld, CTabChanged, PixPatChanged, PortChanged
|
||
IMPORT GDeviceChanged, AllowPurgePixels, NoPurgePixels, GetPixelsState
|
||
IMPORT SetPixelsState, GetPixBaseAddr, NewScreenBuffer, DisposeScreenBuffer
|
||
IMPORT GetGWorldDevice, QDDone, OffscreenVersion, NewTempScreenBuffer
|
||
IMPORT Pixmap32Bit, GetGWorldPixMap
|
||
;----------------------------------------------------------------------------
|
||
; QDExtensions Dispatcher.
|
||
;
|
||
; All Quickdraw extensions routines use a common trap and a selector.
|
||
; The selector is in the low word of D0
|
||
; The size of the parameters is in the high word of D0
|
||
; NOTE: To avoid changing the include files again, functions number 0 through 19
|
||
; are accepted with an unspecified parameter size (high word of D0 cleared).
|
||
; In future versions, any new function should specify the size of parameters.
|
||
;----------------------------------------------------------------------------
|
||
|
||
cmp.w #23,d0 ; if unsigned d0 > max selector,
|
||
bhi.s exit ; don’t do anything
|
||
lsl.w #2,d0 ; turn into jump table offset
|
||
jmp dispatchTable(d0.w) ; jump in jump table
|
||
|
||
dispatchTable
|
||
jmp NewGWorld ; selector 0
|
||
jmp LockPixels ; selector 1
|
||
jmp UnlockPixels ; selector 2
|
||
jmp UpdateGWorld ; selector 3
|
||
jmp DisposeGWorld ; selector 4
|
||
jmp GetGWorld ; selector 5
|
||
jmp SetGWorld ; selector 6
|
||
jmp CTabChanged ; selector 7
|
||
jmp PixPatChanged ; selector 8
|
||
jmp PortChanged ; selector 9
|
||
jmp GDeviceChanged ; selector 10
|
||
jmp AllowPurgePixels ; selector 11
|
||
jmp NoPurgePixels ; selector 12
|
||
jmp GetPixelsState ; selector 13
|
||
jmp SetPixelsState ; selector 14
|
||
jmp GetPixBaseAddr ; selector 15
|
||
jmp NewScreenBuffer ; selector 16
|
||
jmp DisposeScreenBuffer ; selector 17
|
||
jmp GetGWorldDevice ; selector 18
|
||
jmp QDDone ; selector 19
|
||
jmp OffscreenVersion ; selector 20
|
||
jmp NewTempScreenBuffer ; selector 21
|
||
jmp PixMap32Bit ; selector 22
|
||
jmp GetGWorldPixMap ; selector 23
|
||
|
||
exit
|
||
move.l (sp)+,a0 ; get return address
|
||
swap d0 ; get size of parameters in low word
|
||
adda.w d0,sp ; get rid of parameters
|
||
moveq #paramErr,d0 ; return parameter error
|
||
move.w d0,MemErr ; return in low memory, too
|
||
jmp (a0) ; and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
NewGWorld PROC ENTRY
|
||
IMPORT NewGWBuffer
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION NewGWorld (VAR offscreenGWorld: GWorldPtr; pixelDepth: INTEGER;
|
||
; boundsRect: Rect; cTable: CTabHandle; aGDevice:GDHandle;
|
||
; flags: LONGINT): OSErr;
|
||
;
|
||
; Creates an offscreen graphics world, including an offscreen port,
|
||
; an offscreen pixmap, an offscreen buffer, and an optional offscreen device.
|
||
;
|
||
; offscreenGWorld is an output. It is set to a pointer to a CGrafPort
|
||
; with an expanded grafVars substructure. A reference to the offscreen device
|
||
; is put in the grafVars record. If no offscreen device is created, a reference
|
||
; to aGDevice is put in the grafVars record. In both cases, the device is called
|
||
; the attached device.
|
||
;
|
||
; The pixelDepth can be 0,1,2,4,8,16,or 32.
|
||
; If the pixelDepth is 0:
|
||
; The boundsRect is interpreted as a global rectangle in screen space.
|
||
; The depth and color table of the deepest device intersecting
|
||
; with boundsRect is used for the offscreen graphics environment.
|
||
; The port's portRect is set to the same size as boundsRect with the topLeft
|
||
; coordinates set to (0,0).
|
||
; The pixmap's bounds is set to the smallest rectangle enclosing portRect and aligned
|
||
; to the greatest overlapping device with boundsRect (this is to optimize CopyBits
|
||
; between offscreen and screen).
|
||
; The device's gdRect is copied from the pixmap's bounds.
|
||
; If the pixelDepth is 1,2,4,8,16,or 32:
|
||
; The pixmap's bounds, portRect, and device's rect are all set to boundsRect.
|
||
;
|
||
; If pixelDepth is zero, cTable is ignored. Otherwise:
|
||
; If cTable is not nil, it is used as the device and port's color table.
|
||
; If cTable is nil, the default color table for pixelDepth is used
|
||
;
|
||
; Flags contain 2 flag bits:
|
||
; pixPurgeBit = allocate a purgeable offscreen buffer
|
||
; noNewDeviceBit = don't create an offscreen device.
|
||
;
|
||
; If noNewDeviceBit is clear, aGDevice is ignored.
|
||
; If noNewDeviceBit is set, aGDevice is used as the attached device.
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; A6 offsets of parameters after link:
|
||
;
|
||
paramSize equ 22 ; size of parameters
|
||
result equ paramSize+8 ; WORD, OSErr
|
||
offscreenGWorld equ result-4 ; LONG, address of GWorldPtr variable
|
||
pixelDepth equ offscreenGWorld-2 ; WORD, pixel depth
|
||
boundsRect equ pixelDepth-4 ; LONG, address of bound Rectangle
|
||
cTable equ boundsRect-4 ; LONG, handle to color table
|
||
aGDevice equ cTable-4 ; LONG, handle to a device to use as model
|
||
gwFlags equ aGDevice-4 ; LONG, flags
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; A6 offsets of local variables after link:
|
||
;
|
||
|
||
offscreenPixMap equ -4 ; LONG, handle to the offscreen pixmap
|
||
offscreenPort equ offscreenPixMap-4 ; LONG, pointer to the offscreen port
|
||
offscreenDevice equ offscreenPort-4 ; LONG, device returned from NewGWBuffer (always 0)
|
||
localRect equ offscreenDevice-8 ; Rect, rectangle returned from NewGWBuffer
|
||
varSize equ localRect ; size of local variables
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
link a6,#varSize ; allocate local variables
|
||
movem.l d3-d7/a2-a4,-(sp) ; save regs
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Initialize the function result to no error. Optimistically assume that
|
||
; everything will go fine.
|
||
|
||
move.w #noErr,result(a6) ; flag a successful operation,
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Initialize all offscreen local variables to zero.
|
||
; If an error happens during this function, we deallocate the memory for
|
||
; all allocated offscreen variables.
|
||
|
||
clr.l offscreenPixMap(a6) ; handle to offscreen pixmap
|
||
clr.l offscreenPort(a6) ; pointer to the offscreen port
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Check that the boundsRect is not an empty rectangle.
|
||
; If it is empty, don't do anything.
|
||
;
|
||
clr.b -(sp) ; leave room for Boolean result <25JUN90 KON>
|
||
move.l boundsRect(a6),-(sp) ; push address of rectangle on the stack <25JUN90 KON>
|
||
_EmptyRect ; check if rectangle is empty or not <25JUN90 KON>
|
||
move.b (sp)+,d0 ; look at the result <25JUN90 KON>
|
||
bne paramError ; if true, boundsRect is empty, exit with error <25JUN90 KON>
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Allocate memory for port. Do it early on to avoid heap fragmentation.
|
||
; Also, try to allocate it as low as possible in memory.
|
||
; No need to allocate a clear handle, it will be completely filled out by OpenPort.
|
||
|
||
moveq #gwPortSize,d0 ; size of GrafPort
|
||
_NewPtr ; allocate a pointer (no need to clear it)
|
||
bne reportError ; if Memory Manager error, report it and quit
|
||
|
||
move.l a0,offscreenPort(a6) ; save pointer to offscreen port
|
||
move.l a0,a2 ; and keep it around
|
||
|
||
; Initialize the rowBytes field to 0. This field is used in case of
|
||
; memory error to check whether the port has been opened or not (and therefore
|
||
; I need to close it)
|
||
|
||
clr portBits+rowBytes(a0) ; clear the rowBytes field
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Remember the flags in d3
|
||
|
||
move.l gwFlags(a6),d3 ; remember for future use
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Check range validity of pixelDepth -- it must be 0 or 1.
|
||
|
||
move pixelDepth(a6),d7 ; pixel resolution
|
||
cmp.w #1,d7 ; illegal if > 1
|
||
bhi badPixelDepth ; exit with error
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Allocate the pixels.
|
||
|
||
clr.w -(sp) ; make room for result <KON 11FEB90>
|
||
move.l boundsRect(a6),-(sp)
|
||
btst.l #purgePixBit,d3 ; did we need them purged?
|
||
snz -(sp) ; purgeable parameter
|
||
pea offscreenDevice(a6)
|
||
pea offscreenPixMap(a6)
|
||
btst.l #useTempMemBit,d3 ; MF temp memory?
|
||
snz d5 ; pass flag in register
|
||
moveq #31,d6 ; we want slop for re-alignment later
|
||
lea localRect(a6),a3 ; get that localRect in here
|
||
jsr NewGWBuffer
|
||
move.w (sp)+,d0 ; get error return <KON 11FEB90>
|
||
bnz reportError
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Initialize the offscreen port.
|
||
; The port is made to represent accurately the characteristics of the
|
||
; offscreen device (pixmap, color table, etc.)
|
||
|
||
move.l GrafGlobals(a5),a0 ; get address of Quickdraw Globals <1.5>
|
||
move.l thePort(a0),-(sp) ; save the current port <1.5>
|
||
|
||
move.l a2,-(sp) ; push address of offscreen port
|
||
_OpenPort ; initialize port structure
|
||
move.l offscreenPixMap(a6),a0 ; get the offscreen pixmap
|
||
move.l (a0),-(sp) ; dereference
|
||
_SetPBits ; these are the portbits
|
||
;
|
||
; the base address points to our "pixmap" <16MAR90 KON>
|
||
;
|
||
move.l offscreenPixMap(a6),a0 ; get the offscreen pixmap
|
||
move.l a0,portBits+baseAddr(a2) ;<16MAR90 KON>
|
||
|
||
move.l GrafGlobals(a5),a0 ; get address of Quickdraw Globals <1.5>
|
||
move.l (sp)+,thePort(a0) ; set the current port <1.5>
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Set the portRect field of the GrafPort to localRect,
|
||
; Note that:
|
||
; if pixelDepth is 0:
|
||
; localRect = boundsRect offset so that topLeft = (0,0)
|
||
; if pixelDepth is non 0:
|
||
; localRect = boundsRect
|
||
|
||
computePortRect
|
||
move.l topLeft(a3),portRect+topLeft(a2) ; copy localRect to portRect
|
||
move.l botRight(a3),portRect+botRight(a2)
|
||
|
||
; Set visible region of offscreen port to portRect
|
||
|
||
move.l visRgn(a2),-(sp) ; push handle to visRgn
|
||
pea portRect(a2) ; push address of portRect
|
||
_RectRgn ; make visRgn = portRect
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Store the offscreen port in the GWorldPtr variable
|
||
|
||
move.l offscreenPixMap(a6),a0
|
||
move.l a0,gwPortPixMap(a2) ; store a pointer to the PixMap after the port
|
||
move.l (a0),a0
|
||
move.l a2,gwPMPort(a0) ; store a pointer to the port after the PixMap
|
||
|
||
move.l offscreenGWorld(a6),a0 ; get pointer to offscreen GWorld variable
|
||
move.l a2,(a0) ; store in it the pointer to the offscreen port
|
||
|
||
;-------------------------------------------------------------------------
|
||
; We're done. Return error code and put a copy of it in low-memory MemErr.
|
||
|
||
goHome
|
||
move result(a6),d0 ; copy error code to d0 <21Jun89> JCM
|
||
move d0,MemErr ; copy error code to low-memory global MemErr <21Jun89> JCM
|
||
movem.l (sp)+,d3-d7/a2-a4 ; restore regs
|
||
unlk a6 ; get rid of stack frame
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
;-------------------------------------------------------------------------
|
||
; When an error occurs, all allocated memory is freed and an error code
|
||
; is returned.
|
||
|
||
badPixelDepth
|
||
move #cDepthErr,result(a6) ; pixel depth invalid
|
||
bra.s disposOffscreenHandles ; release memory and exit
|
||
|
||
paramError
|
||
move #paramErr,result(a6) ; one of the parameters is invalid
|
||
bra.s disposOffscreenHandles ; release memory and exit
|
||
|
||
reportError
|
||
move d0,result(a6) ; directly report Memory Manager error
|
||
|
||
; Dispose of all allocated memory (handle is allocated when non zero)
|
||
; If the port has been opened, close it and then dispose of the actual port structure
|
||
|
||
disposOffscreenHandles
|
||
|
||
move.l offscreenPixMap(a6),-(sp) ; get handle to offscreen buffer
|
||
_DisposeScreenBuffer ; dispose it
|
||
move.l offscreenPort(a6),d7 ; get handle to offscreen port
|
||
beq.s goHome ; if nil, don't do anything
|
||
move.l d7,a0 ; if not nil, check if the port has been opened
|
||
move portBits+rowBytes(a0),d0 ; get rowBytes
|
||
bz.s @noClose ; if 0, don’t close port
|
||
move.l (a0),-(sp) ; push pointer to port
|
||
_ClosePort ; close it down
|
||
@noClose
|
||
move.l d7,a0 ; get handle to offscreen port
|
||
_DisposPtr ; dispose it
|
||
bra.s goHome ; exit
|
||
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
GetGWorld PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE GetGWorld (VAR port: CGrafPtr; VAR gdh: GDHandle);
|
||
;
|
||
; Return the current port and gDevice.
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 8 ; size of parameters
|
||
port equ paramSize+4-4 ; LONG, address of CGrafPtr variable
|
||
gdh equ port-4 ; LONG, address of GDHandle variable
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
move.l port(sp),a0 ; get address of port variable
|
||
move.l GrafGlobals(a5),a1 ; get address of Quickdraw Globals
|
||
move.l thePort(a1),(a0) ; put the current port in port variable
|
||
|
||
move.l gdh(sp),a0 ; get address of device variable
|
||
clr.l (a0) ; no devices here
|
||
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
|
||
DisposeGWorld PROC EXPORT
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE DisposeGWorld (offscreenGWorld: GWorldPtr);
|
||
;
|
||
; Dispose all the memory allocated for the offscreen graphics world
|
||
; described by offscreenGWorld.
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 4 ; size of parameters
|
||
offscreenGWorld equ paramSize+4-4 ; LONG, offscreen graphics world
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; Dispose of the buffer
|
||
|
||
move.l offscreenGWorld(sp),a0 ; get pointer to port
|
||
move.l gwPortPixMap(a0),-(sp) ; get handle to pixmap
|
||
_DisposeScreenBuffer ;
|
||
|
||
; Dispose of all substructures of the offscreen port
|
||
|
||
move.l offscreenGWorld(sp),-(sp) ; push pointer to offscreen port
|
||
_ClosePort ; get rid of all substructures
|
||
|
||
move.l offscreenGWorld(sp),a0 ; get pointer to grafport
|
||
_DisposPtr ; dispose memory of grafport structure
|
||
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
UpdateGWorld PROC EXPORT
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION UpdateGWorld (VAR offscreenGWorld: GWorldPtr; pixelDepth: INTEGER;
|
||
; boundsRect: Rect; cTable: CTabHandle; aGDevice: GDHandle;
|
||
; flags: LONGINT): LONGINT;
|
||
;
|
||
; Update the given graphics world to the new conditions (pixelDepth, boundsRect,
|
||
; color table, and optionally aGDevice).
|
||
;
|
||
; offscreenGWorld is both input and output. A pointer to the new GWorld is returned
|
||
; in offscreenGWorld.
|
||
;
|
||
; Flags determine how the pixels are preserved. It contains the following bits:
|
||
; clipPixBit = clip the pixels to the new boundsRect.
|
||
; stretchPixBit = stretch or shrink the pixels to the new boundsRect.
|
||
; ditherPixBit = dither the pixels
|
||
;
|
||
; clipPixBit and stretchPixBit are mutually exclusive.
|
||
; If flags is 0, no update occurs.
|
||
; Possible combinations are:
|
||
; 0, clipPixMask, stretchPixMask, clipPixMask+ditherPixMask, stretchPixMask+ditherPixMask
|
||
;
|
||
; PixelDepth, boundsRect, and cTable work in the same way as in NewGWorld.
|
||
;
|
||
; If aGDevice is not NIL, pixelDepth and cTable are ignored, and aGDevice's pixel depth
|
||
; and color table are used instead.
|
||
;
|
||
; If offscreenGWorld doesn't have an offscreen device and aGDevice is not NIL, aGDevice
|
||
; becomes the new attached device.
|
||
;
|
||
; UpdateGWorld returns an error code if it failed, 0 if it didn't do anything, and
|
||
; a positive number if it succeeded. This number describes what actions UpdateGWorld performed
|
||
; with the following bits:
|
||
;
|
||
; mapPixBit = set if color table mapping occurred
|
||
; newDepthBit = set if pixels were scaled to a different depth
|
||
; alignPixBit = set if pixels were realigned to screen alignment
|
||
; newRowBytesBit = set if pixmap was reconfigured in a new rowBytes
|
||
; reallocPixBit = set if offscreen buffer had to be reallocated
|
||
; clipPixBit = set if pixels were or are to be clipped
|
||
; stretchPixBit = set if pixels were or are to be stretched/shrinked
|
||
; ditherPixBit = set if pixels were or are to be dithered
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; A6 offsets of parameters after link:
|
||
;
|
||
paramSize equ 22 ; size of parameters
|
||
result equ paramSize+8 ; LONG, QDErr or flags
|
||
offscreenGWorld equ result-4 ; LONG, address of offscreen GWorldPtr variable
|
||
pixelDepth equ offscreenGWorld-2 ; WORD, new pixel depth
|
||
boundsRect equ pixelDepth-4 ; LONG, address of new bound Rectangle
|
||
cTable equ boundsRect-4 ; LONG, handle to new color table
|
||
aGDevice equ cTable-4 ; LONG, handle to device to use instead of pixelDepth and cTable
|
||
gwFlags equ aGDevice-4 ; LONG, defines pixel transfer
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; A6 offsets of local variables after link:
|
||
;
|
||
|
||
newGWorld equ -4 ; LONG, new offscreen GWorld
|
||
clipSrcRect equ newGWorld-8 ; Rect, srcRect clipped
|
||
clipDstRect equ clipSrcRect-8 ; Rect, same size as srcRect, but in dstRect coordinates
|
||
newFlags equ clipDstRect-4 ; LONG, contains purgePixBit and noNewDeviceBit
|
||
state equ newFlags-4 ; LONG, lock/purge state of pixels
|
||
purged equ state-1 ; BYTE, true if offscreen buffer has been purged
|
||
sameBounds equ purged-1 ; BYTE, true if the portRects of old and new gworlds are the same
|
||
savePort equ sameBounds-4 ; LONG, pointer to saved port
|
||
newBounds equ savePort-8 ; Rect, boundsRect converted to portRect
|
||
horizOffset equ newBounds-2 ; WORD, alignment of new offscreen pixmap
|
||
newGWRowBytes equ horizOffset-2 ; WORD, rowBytes of new offscreen gworld
|
||
oldBufSize equ newGWRowBytes-4 ; LONG, size of old offscreen buffer
|
||
saveClip equ oldBufSize-4 ; LONG, handle to saved clip region
|
||
varSize equ saveClip ; size of local variables
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
link a6,#varSize ; allocate local variables
|
||
movem.l a2-a4/d5-d7,-(sp) ; save regs
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Initialize the flags
|
||
|
||
clr.l result(a6) ; Assume no error and nothing to do
|
||
clr.l newFlags(a6) ; initialize flags for NewGWorld
|
||
|
||
; Check that clipPixBit and stretchPixBit are not both set in the gwFlags
|
||
|
||
move.l gwFlags(a6),d0 ; get the flags
|
||
and.l #clipPix+stretchPix,d0 ; get clipPixBit and stretchPixBit
|
||
cmp.l #clipPix+stretchPix,d0 ; if both bit are set, quit with parameter error
|
||
beq paramError ; report error and quit
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Remember pointer to offscreen GWorld
|
||
|
||
getOffGWorld
|
||
move.l offscreenGWorld(a6),a3
|
||
move.l (a3),a3 ; get pointer to offscreen GWorld
|
||
|
||
; Save the current graphics world
|
||
|
||
pea savePort(a6) ; push address of savePort
|
||
_GetPort
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Compute new portRect and get new pixSize and color table seed for new offscreen graphics world
|
||
|
||
getNewParms
|
||
move.l boundsRect(a6),a0 ; get pointer to boundsRect
|
||
|
||
; Check range validity of pixelDepth -- it must be between 0 or 1.
|
||
|
||
move pixelDepth(a6),d7 ; pixel resolution
|
||
beq.s useMaxDevice ; if depth = 0, find max resolution
|
||
cmp #1,d7 ; illegal if > 0
|
||
bhi badPixelDepth ; exit with error
|
||
bra.s boundsIsLocal ; no, just copy boundsRect as is
|
||
|
||
;----------------------------------------------------------------------------
|
||
; If pixelDepth = 0:
|
||
; Offset boundsRect in newBounds so that topLeft = (0,0)
|
||
|
||
useMaxDevice
|
||
clr.l newBounds+topLeft(a6)
|
||
move bottom(a0),d0 ; compute newBounds.bottom = boundsRect->bottom - boundsRect->top
|
||
sub top(a0),d0
|
||
move d0,newBounds+bottom(a6)
|
||
move right(a0),d0 ; compute newBounds.right = boundsRect->right - boundsRect->left
|
||
sub left(a0),d0
|
||
move d0,newBounds+right(a6)
|
||
|
||
; Get new pixmap alignment with the max device
|
||
|
||
move.l boundsRect(a6),a0 ; get pointer to boundsRect
|
||
move left(a0),d0 ; get left coordinate of boundsRect
|
||
move d0,horizOffset(a6) ; save offset
|
||
|
||
bra.s checkPixShift
|
||
|
||
;----------------------------------------------------------------------------
|
||
; pixelDepth is 1:
|
||
; Copy boundsRect to newBounds without modification
|
||
|
||
boundsIsLocal
|
||
move.l topLeft(a0),newBounds+topLeft(a6) ; copy boundsRect to newBounds
|
||
move.l botRight(a0),newBounds+botRight(a6)
|
||
|
||
; Alignment is 0
|
||
|
||
clr horizOffset(a6) ; no alignment if boundsRect is not global
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Convert pixel depth to shift amount
|
||
; Use ShiftTbl for conversion
|
||
|
||
checkPixShift
|
||
|
||
; Convert horizOffset to a number of pixels such that the equivalent number of bits is modulo 32
|
||
|
||
and #$1F,horizOffset(a6) ; save back in horizOffset <19Jun89> JCM
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Get rowBytes from old port, assume it will not change
|
||
|
||
move portBits+rowBytes(a3),newGWRowBytes(a6) ; assume rowBytes doesn't change
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Compare the portRects of the old and new world.
|
||
; If same, set the sameBounds flag
|
||
|
||
clr.b sameBounds(a6) ; assume portRects are different
|
||
move.l portRect+topLeft(a3),d0 ; get the topLeft coordinates of the old gworld
|
||
cmp.l newBounds+topLeft(a6),d0 ; compare with topLeft coordinates of new gworld
|
||
bne.s compareSize
|
||
move.l portRect+botRight(a3),d0 ; get the botRight coordinates of the old gworld
|
||
cmp.l newBounds+botRight(a6),d0 ; compare with botRight coordinates of new gworld
|
||
bne.s compareSize
|
||
|
||
move.b #true,sameBounds(a6) ; rectangles are equal, set the sameBounds flag
|
||
bra.s checkAlignment ; skip comparing size
|
||
|
||
;----------------------------------------------------------------------------
|
||
; If different size, set clipPixBit or stretchPixBit depending on flags
|
||
|
||
compareSize
|
||
move portRect+right(a3),d0 ; calculate old port's width (a3 = old GWorldPtr)
|
||
sub portRect+left(a3),d0
|
||
move newBounds+right(a6),d1 ; calculate new port's width
|
||
sub newBounds+left(a6),d1
|
||
cmp d0,d1 ; are widths the same?
|
||
bne.s checkRowBytes ; no, check the rowBytes
|
||
|
||
move portRect+bottom(a3),d0 ; calculate old port's height
|
||
sub portRect+top(a3),d0
|
||
move newBounds+bottom(a6),d1 ; calculate new port's height
|
||
sub newBounds+top(a6),d1
|
||
cmp d0,d1 ; are heights the same?
|
||
beq.s checkAlignment ; yes, portRect's are same size, no clipping/stretching
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Compute rowBytes of new world.
|
||
; Compare the rowBytes of the old and new world.
|
||
; If different, set newRowBytesBit
|
||
; Then, set the clipPixBit or stretchPixBit
|
||
|
||
checkRowBytes
|
||
move newBounds+right(a6),d0 ; compute pixmap.bounds.right - pixmap.bounds.left
|
||
sub newBounds+left(a6),d0 ; don't take into account alignment
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Allocate the actual offscreen buffer.
|
||
; rowBytes is computed as the smallest number of longs containing one line of pixel + 31 bits,
|
||
; converted to bytes:
|
||
; (((localRect.right - localRect.left) * pixelSize + 31 + 31) / 32) * 4
|
||
;
|
||
; NOTE 1: Adding 31 bits gives us some leg room if we want to realign the pixmap in UpdateGWorld.
|
||
; The additional 31 bits are to force a round-up top the next long (as usual).
|
||
; NOTE 2: localRect is used instead of pixmapBounds because rowBytes is computed independently
|
||
; of the current alignment but for all possible alignments.
|
||
; NOTE 3: The above formula for rowBytes can be simplified in:
|
||
; (((localRect.right-localRect.left) * pixelSize + 30) / 32 + 1) * 4
|
||
|
||
ext.l d0 ; convert to long
|
||
lsl.l d7,d0 ; convert pixels to bits (pixShift is in d7)
|
||
add.l #30,d0 ; add 30 bits as per simplified formula above
|
||
lsr.l #5,d0 ; convert bits to longs
|
||
addq.w #1,d0 ; add one long as per simplified formula above
|
||
lsl.w #2,d0 ; convert longs to bytes
|
||
move.w d0,newGWRowBytes(a6) ; save # of bytes in a row
|
||
|
||
; Compare the rowBytes of the old and new world and set the newRowBytesBit if different
|
||
|
||
cmp.w portBits+rowBytes(a3),d0 ; if different, set newRowBytes bit
|
||
beq.s setClipStretchBit ; same rowBytes, don't set newRowBytes bit
|
||
or.l #newRowBytes,result(a6) ; set newRowBytes bit
|
||
|
||
;----------------------------------------------------------------------------
|
||
; PortRects of old and new world are of different sizes, decide between clip and stretch
|
||
|
||
setClipStretchBit
|
||
move.l gwFlags(a6),d0 ; get flags
|
||
and.l #clipPix,d0 ; is the clipPixBit set?
|
||
bne.s @0 ; yes, use clipping
|
||
move.l #stretchPix,d0 ; no, use stretching
|
||
@0
|
||
or.l d0,result(a6) ; store bits in result <1.6>
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Compare the left coordinates of the portPixMap->bounds of the old and new world.
|
||
; If different, assume alignment is taking place (don't bother getting with
|
||
; max area device and checking that alignment might still be the same)
|
||
|
||
checkAlignment
|
||
move.w portBits+bounds+left(a3),d0 ; get bounds.left of old pixmap
|
||
move.w horizOffset(a6),d1 ; get alignment of new pixmap
|
||
neg.w d1 ; the algebraic opposite is the bounds.left of the new pixmap
|
||
cmp.w d1,d0 ; compare them both
|
||
beq.s @noAlignment ; identical, no alignment
|
||
or.l #alignPix,result(a6) ; different, set alignment bit
|
||
@noAlignment
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Get state of offscreen buffer
|
||
|
||
getState
|
||
clr.l -(sp) ; leave room for flags result
|
||
move.l gwPortPixMap(a3),-(sp) ; push handle to pixmap
|
||
_GetPixelsState ; get state of pixels
|
||
move.l (sp)+,d0 ; get the result
|
||
move.l d0,state(a6) ; remember it for later
|
||
|
||
; Prevent purging of the offscreen buffer for the time of UpdateGWorld
|
||
|
||
move.l gwPortPixMap(a3),-(sp) ; push handle to pixmap
|
||
_NoPurgePixels ; don't purge the pixels
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Set purgePixBit in the flags for NewGWorld if the pixels are purgeable or purged
|
||
; Set reallocPixBit in the result of UpdateGWorld if the pixels are purged
|
||
|
||
clr.b purged(a6) ; assume pixels aren't purged
|
||
|
||
clr.l -(sp) ; leave room for Ptr result
|
||
move.l gwPortPixMap(a3),-(sp) ; push handle to pixmap
|
||
_GetPixBaseAddr ; get address of offscreen buffer
|
||
move.l (sp)+,d0 ; put it in d0
|
||
bne.s notPurged ; offscreen buffer hasn't been purged
|
||
|
||
or.l #purgePix,newFlags(a6) ; offscreen buffer is purged, it means it's purgeable
|
||
or.l #reallocPix,result(a6) ; flag that we had to reallocate the pixels
|
||
|
||
; Remember that offscreen buffer is purged.
|
||
; GetPixelsState returns an error if the offscreen buffer is purged.
|
||
; Changed the result of GetPixelsState to a long with the purge bit set.
|
||
; (lock bit wasn't set before the purge or buffer wouldn't have been purged)
|
||
|
||
move.b #true,purged(a6) ; remember that offscreen buffer is purged
|
||
move.l #pixelsPurgeable,state(a6) ; if the pixels are purged, recompute state
|
||
|
||
bra.s testMFTempPixels
|
||
|
||
notPurged
|
||
move.l state(a6),d0 ; get the state of the pixels
|
||
btst.l #pixelsPurgeableBit,d0 ; is the pixelsPurgeableBit set?
|
||
beq.s @notPurgeable ; no, don't set purgePixBit in the flags
|
||
|
||
or.l #purgePix,newFlags(a6) ; offscreen buffer is purgeable, set the purgePixBit
|
||
@notPurgeable
|
||
|
||
; If the pixels are allocated in MultiFinder temp memory (as indicated in the <07Jul89> JCM
|
||
; grafVars), set the useTempMemBit in the flags for NewGWorld. <07Jul89> JCM
|
||
|
||
testMFTempPixels
|
||
move.l gwPortPixMap(a3),a0 ; get handle to pixmap
|
||
move.l (a0),a0 ; get pointer to pixmap
|
||
tst.b gwPMUseMFTemp(a0) ; test useMFTemp flag in grafVars <07Jul89> JCM
|
||
beq.s dispatchFlags ; not set, don't set useMFTempBit <07Jul89> JCM
|
||
or.l #useTempMem,newFlags(a6) ; set useMFTempBit <07Jul89> JCM
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Look at the result flags and find if we can use optimized algorithms
|
||
; Currently optimized cases are:
|
||
; 0. Nothing needs to be done (just exit and return 0)
|
||
; 1. Pixels have been purged (nothing else changes)
|
||
; 2. Pixels need to be realigned (but boundsRect's size doesn't change)
|
||
|
||
dispatchFlags
|
||
move.l result(a6),d0 ; get the result flags
|
||
beq.s nothingToDo ; if no bit set, there is nothing to do
|
||
|
||
cmp.l #reallocPix,d0 ; is reallocPixBit the only bit set?
|
||
beq.s reallocBuffer ; yes, just reallocate the offscreen buffer
|
||
|
||
; The following cases are relevant only if the pixels are to be preserved
|
||
; If the pixels are not to be preserved, just dispose of the old gworld and create a new one
|
||
|
||
tst.l gwFlags(a6) ; is any update flag set?
|
||
beq updatePixels ; nope, go dispose of old gworld and create a new one
|
||
|
||
cmp.l #alignPix,d0 ; is alignPixBit the only bit set?
|
||
beq.s realignPixels ; yes, just realign the pixels and pixmap
|
||
|
||
bra updatePixels ; none of these cases apply, use regular case
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Nothing at all has changed in the offscreen gworld.
|
||
|
||
nothingToDo
|
||
move.l a3,newGWorld(a6) ; that's it, we already have the new gworld
|
||
|
||
bra setState ; set the state of the offscreen buffer and quit
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Nothing has changed in the offscreen gworld except that the pixels have been purged
|
||
; Reallocate them and put the handle in the baseAddr of the pixmap.
|
||
; NOTE: If the pixels are purged, the pmVersion of the pixmap is always PixMapVers2 (LockPixels
|
||
; doesn't set the pmVersion to PixMapVers1 if the pixels are purged), therefore, the handle
|
||
; is the appropriate thing to put in the baseAddr.
|
||
|
||
reallocBuffer
|
||
move newBounds+bottom(a6),d0 ; compute height = bottom-top
|
||
sub newBounds+top(a6),d0
|
||
mulu.w newGWRowBytes(a6),d0 ; compute height * rowBytes
|
||
|
||
move.l gwPortPixMap(a3),a1
|
||
move.l (a1),a1 ; get pointer to offscreen pixmap
|
||
move.l baseAddr(a1),a0 ; get handle to offscreen buffer from offscreen pixmap
|
||
_ReallocHandle ; allocate offscreen buffer (could be in MFTemp memory)
|
||
bne reportError ; if Memory Manager error, report it and quit
|
||
|
||
_MoveHHi ; move the buffer as high as possible in memory
|
||
|
||
move.l a3,newGWorld(a6) ; that's it, we already have the new gworld
|
||
|
||
bra setState ; set the state of the offscreen buffer and quit
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Nothing has changed in the offscreen gworld except that the boundsRect
|
||
; has been moved around (while keeping the same size).
|
||
; The algorithm realigns all the pixels. No mask is used for the edges because they
|
||
; contain unused pixels.
|
||
|
||
realignPixels
|
||
|
||
; Update the port pixmap's bounds to the newBounds with alignment
|
||
|
||
move.l gwPortPixMap(a3),a2 ; get handle to pixmap
|
||
move.l (a2),a4 ; get pointer to pixmap
|
||
move newBounds+top(a6),bounds+top(a4) ; put new bounds.top
|
||
move newBounds+left(a6),d0 ; compute left coordinate with alignment
|
||
sub horizOffset(a6),d0
|
||
move d0,bounds+left(a4) ; put new bounds.left
|
||
move.l newBounds+botRight(a6),bounds+botRight(a4) ; put new bounds.botRight
|
||
|
||
; Set up the base address without locking (oooh...)
|
||
|
||
move.l baseAddr(a4),d3 ; save the current base address (or handle)
|
||
subq.w #4,sp ; leave room for result
|
||
move.l a2,-(sp) ; push handle to pixmap
|
||
_GetPixBaseAddr ; get address of pixels
|
||
move.l (sp)+,a1 ; keep address in a1
|
||
move.l a1,portBits+baseAddr(a3) ; jam it in the portBits
|
||
move.l a1,baseAddr(a4) ; jam it in the pixmap
|
||
|
||
; Save the port, set it to no port, so we don’t get StdBits
|
||
|
||
move.l GrafGlobals(a5),a0 ; get the port
|
||
move.l thePort(a0),d4 ; save for later
|
||
clr.l thePort(a0) ; set to no port
|
||
|
||
; Copy the bits over a few pixels (srcRect = newBounds, dstRect = pixMap^^.bounds)
|
||
|
||
pea portBits(a3) ; srcBits = portBits (old bounds)
|
||
move.l a4,-(sp) ; dstBits = pixMap^ (new bounds)
|
||
pea portBits+bounds(a3) ; srcRect = srcBits.bounds
|
||
pea bounds(a4) ; dstRect = dstPix.bounds
|
||
move.w #srcCopy,-(sp)
|
||
clr.l -(sp)
|
||
_CopyBits ; slide them over
|
||
|
||
; Restore the port
|
||
|
||
move.l GrafGlobals(a5),a0 ; get the port
|
||
move.l d4,thePort(a0)
|
||
|
||
; Restore the base address
|
||
|
||
move.l d3,baseAddr(a4) ; jam it in the pixmap
|
||
move.l d3,portBits+baseAddr(a3) ; jam it in the portBits, just in case it is locked
|
||
|
||
; Update the port’s portBits.bounds to the newBounds with alignment (in pixMap.bounds)
|
||
|
||
move.l bounds+topLeft(a4),portBits+bounds+topLeft(a3)
|
||
move.l bounds+botRight(a4),portBits+bounds+botRight(a3)
|
||
|
||
; Update the port’s portRect to the newBounds without alignment
|
||
|
||
move.l newBounds+topLeft(a6),portRect+topLeft(a3) ; copy newBounds to portRect
|
||
move.l newBounds+botRight(a6),portRect+botRight(a3)
|
||
|
||
; Set visible region of offscreen port to portRect
|
||
|
||
move.l visRgn(a3),-(sp) ; push handle to visRgn
|
||
pea portRect(a3) ; push address of portRect
|
||
_RectRgn ; make visRgn = portRect
|
||
|
||
; Return the old GWorld into the newGWorld
|
||
|
||
move.l a3,newGWorld(a6) ; GWorld hasn't changed
|
||
|
||
bra setState ; we're done, go set the state of the offscreen buffer and quit
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Create a new graphics world and, if necessary, CopyBits the old graphics world into the new one
|
||
|
||
updatePixels
|
||
|
||
; Update the flags in result according to the update flags passed to UpdateGWorld
|
||
; We're going to realloc the offscreen
|
||
|
||
or.l #reallocPix,result(a6) ; flag that we had to reallocate the pixels <KON 11FEB91>
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Dispose of old offscreen buffer if no CopyBits will take place.
|
||
; Don't dispose of the old graphics world (in case NewGWorld fails).
|
||
|
||
testUpdate
|
||
move.l MinusOne,oldBufSize(a6) ; initialize to -1 (assume old offscreen not disposed of)
|
||
|
||
tst.b purged(a6) ; are the pixels purged?
|
||
bne.s @0 ; yes, dispose of the old graphics world
|
||
move.l gwFlags(a6),d0 ; get flags
|
||
bne.s createNew ; if there is update to do, don't dispose old GWorld
|
||
@0
|
||
move.l gwPortPixMap(a3),a4 ; get handle to old pixmap
|
||
|
||
move.l a4,-(sp) ; push it
|
||
_UnlockPixels ; unlock pixels so we have a handle in baseAddr
|
||
|
||
move.l (a4),a1 ; get pointer to pixmap
|
||
move.l baseAddr(a1),a4 ; get handle to offscreen buffer
|
||
|
||
clr.l baseAddr(a1) ; clear it to mark that it's disposed
|
||
|
||
move.l a4,a0 ; get offscreen buffer handle in a0
|
||
_GetHandleSize ; get size of offscreen buffer
|
||
move.l d0,oldBufSize(a6) ; remember it in case NewGWorld fails
|
||
|
||
move.l a4,a0
|
||
_DisposHandle ; get rid of old offscreen buffer
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Create a new graphics world
|
||
|
||
createNew
|
||
clr -(sp) ; leave room for result
|
||
pea newGWorld(a6) ; push address of new offscreen GWorldPtr variable
|
||
move pixelDepth(a6),-(sp) ; new pixel depth
|
||
move.l boundsRect(a6),-(sp) ; new bound rectangle
|
||
move.l cTable(a6),-(sp) ; new color table
|
||
move.l aGDevice(a6),-(sp) ; pass aGDevice (NIL if noNewDeviceBit is clear)
|
||
move.l newFlags(a6),-(sp) ; flags with appropriate noNewDeviceBit and purgePixBit
|
||
_NewGWorld ; create a new GWorld
|
||
move (sp)+,d0 ; look at result
|
||
bne newGWorldError ; an error happened, handle it properly
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Update new grafport with fields from old grafport
|
||
|
||
move.l newGWorld(a6),a4 ; get pointer to new grafport
|
||
|
||
if 0 then
|
||
; Update clipRgn by:
|
||
; offsetting it to the new portRect if clipPixBit set
|
||
; mapping it to the new portRect if stretchPixBit set
|
||
|
||
_MaxBlock ; get maximum space left in heap
|
||
move.l d0,d3 ; save it
|
||
move.l clipRgn(a3),a0 ; get size of clipRgn
|
||
_GetHandleSize
|
||
cmp.l d0,d3 ; is there enough space in heap?
|
||
blt purgedError ; no => branch to noMem error
|
||
endif
|
||
|
||
move.l clipRgn(a3),-(sp) ; first copy clip region
|
||
move.l clipRgn(a4),-(sp)
|
||
_CopyRgn
|
||
|
||
move.l gwFlags(a6),d0 ; get the flags
|
||
and.l #clipPix,d0 ; look at the clipPixBit
|
||
bne.s offsetClip ; clipPixBit set, offset the clip region
|
||
|
||
; Map clipRgn to the new portRect
|
||
|
||
move.l clipRgn(a4),-(sp) ; push handle to clip Region
|
||
pea portRect(a3) ; push address of old portRect
|
||
pea portRect(a4) ; push address of new portRect
|
||
_MapRgn ; map region from old portRect to new portRect
|
||
bra.s copyPixPats
|
||
|
||
; Offset clipRgn to the new portRect
|
||
|
||
offsetClip
|
||
move.l clipRgn(a4),-(sp) ; push handle to clip Region
|
||
move portRect+left(a4),d0 ; compute offset between left coordinates of old and new portRect
|
||
sub portRect+left(a3),d0
|
||
move d0,-(sp)
|
||
move portRect+top(a4),d0 ; compute offset between top coordinates of old and new portRect
|
||
sub portRect+top(a3),d0
|
||
move d0,-(sp)
|
||
_OfsetRgn ; offset the region
|
||
|
||
; Copy the patterns, pen characteristics, etc.
|
||
|
||
copyPixPats
|
||
lea bkPat(a4),a0 ; copy from the old port
|
||
lea bkPat(a3),a1 ; into the new port
|
||
moveq #portRec-bkPat,d0 ; copy this much of the port
|
||
_BlockMove
|
||
|
||
;----------------------------------------------------------------------------
|
||
; If the pixels in the old world are purged, don't update them
|
||
|
||
tst.b purged(a6) ; are the old pixels purged?
|
||
bne noCopyBits ; yes, don't CopyBits
|
||
|
||
; If flags is not 0, find out how the pixels will be updated and call CopyBits to update them
|
||
|
||
move.l gwFlags(a6),d0 ; if flags is 0,
|
||
beq noCopyBits ; just set state of new offscreen buffer and return
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Lock the pixels of both gworlds
|
||
|
||
clr.b -(sp) ; leave room for Boolean result
|
||
move.l gwPortPixMap(a3),-(sp) ; handle to old offscreen PixMap
|
||
_LockPixels ; lock the pixels down
|
||
move.b (sp)+,d0 ; ignore result (if we're here, it means pixels are not purged)
|
||
|
||
clr.b -(sp) ; leave room for Boolean result
|
||
move.l newGWorld(a6),a0 ; get pointer to new offscreen GWorld
|
||
move.l gwPortPixMap(a0),-(sp) ; push handle to new offscreen PixMap
|
||
_LockPixels ; lock the pixels down
|
||
move.b (sp)+,d0 ; if pixels are purged already, quit now
|
||
beq purgedError ; report error and exit
|
||
|
||
; Set current graphics world to new GWorld
|
||
|
||
move.l newGWorld(a6),-(sp) ; push pointer to new GWorld
|
||
clr.l -(sp) ; NIL device
|
||
_SetGWorld ; set current GWorld for CopyBits
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Save the clipRgn of the newGWorld and set it to newGWorld's portRect
|
||
; so that CopyBits copies the whole pixmap
|
||
|
||
clr.l -(sp) ; leave room for RgnHandle result
|
||
_NewRgn ; create a new region for saveClip
|
||
move.l (sp),saveClip(a6) ; remember region handle in saveClip
|
||
|
||
_GetClip ; get the current clipRgn in saveClip
|
||
|
||
move.l newGWorld(a6),a0 ; get pointer to new GWorld
|
||
pea portRect(a0) ; push address of portRect
|
||
_ClipRect ; set clipRgn to portRect
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Call CopyBits to update the pixels. Compute srcRect and dstRect according
|
||
; to update mode (clipping or stretching)
|
||
|
||
pea portBits(a3) ; srcBits = pointer to old pixmap
|
||
move.l newGWorld(a6),a1 ; get pointer to new offscreen port
|
||
pea portBits(a1) ; dstBits = pointer to new pixmap
|
||
|
||
lea portRect(a3),a0 ; get address of old portRect
|
||
lea portRect(a1),a1 ; get address of new portRect
|
||
|
||
move.l gwFlags(a6),d0 ; get the flags
|
||
btst.l #stretchPixBit,d0 ; is stretchPixBit set?
|
||
bne.s doCopyBits ; yes, use srcRect and dstRect with no clipping
|
||
|
||
; If clipPixBit is set, clip CopyBits to size of destination rectangle
|
||
|
||
doClipping
|
||
|
||
move.l topLeft(a0),clipSrcRect+topLeft(a6) ; topLeft coordinates remain the same
|
||
move.l topLeft(a1),clipDstRect+topLeft(a6)
|
||
|
||
; Compute smallest height of old and new rectangle
|
||
|
||
move bottom(a0),d0 ; compute old height
|
||
sub top(a0),d0
|
||
move bottom(a1),d1 ; compute new height
|
||
sub top(a1),d1
|
||
cmp d0,d1 ; which height is smaller?
|
||
blt.s @0 ; new height is smaller, keep in d1
|
||
move d0,d1 ; old height is smaller, keep in d1
|
||
@0
|
||
move top(a0),d0 ; compute old top + clipped height
|
||
add d1,d0
|
||
move d0,clipSrcRect+bottom(a6) ; store in clipSrcRect.bottom
|
||
move top(a1),d0 ; compute new top + clipped height
|
||
add d1,d0
|
||
move d0,clipDstRect+bottom(a6) ; store in clipDstRect.bottom
|
||
|
||
; Compute smallest width of old and new rectangle
|
||
|
||
move right(a0),d0 ; compute old width
|
||
sub left(a0),d0
|
||
move right(a1),d1 ; compute new width
|
||
sub left(a1),d1
|
||
cmp d0,d1 ; which width is smaller?
|
||
blt.s @1 ; new width is smaller, keep in d1
|
||
move d0,d1 ; old width is smaller, keep in d1
|
||
@1
|
||
move left(a0),d0 ; compute old left + clipped width
|
||
add d1,d0
|
||
move d0,clipSrcRect+right(a6) ; store in clipSrcRect.right
|
||
move left(a1),d0 ; compute new left + clipped width
|
||
add d1,d0
|
||
move d0,clipDstRect+right(a6) ; store in clipDstRect.right
|
||
|
||
lea clipSrcRect(a6),a0 ; srcRect = smallest of old portRect and new portRect
|
||
lea clipDstRect(a6),a1 ; dstRect = idem but in coordinate system of new port
|
||
|
||
doCopyBits
|
||
move.l a0,-(sp) ; srcRect = old portRect (clipped or unclipped)
|
||
move.l a1,-(sp) ; dstRect = new portRect
|
||
move.w #srcCopy,-(sp) ; mode = srcCopy or dither
|
||
move.l #nil,-(sp) ; no mask
|
||
_CopyBits ; transfer the pixels
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Restore the clipRgn of the newGWorld
|
||
|
||
move.l saveClip(a6),-(sp) ; push handle to saveClip
|
||
_SetClip ; restore clipRgn
|
||
|
||
move.l saveClip(a6),-(sp) ; push handle to saveClip
|
||
_DisposRgn ; get rid of clipRgn
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Unlock the pixels of the new offscreen GWorld (don't care about the old one, we'll get rid of it)
|
||
|
||
move.l newGWorld(a6),a0 ; get pointer to new offscreen GWorld
|
||
move.l gwPortPixMap(a0),-(sp) ; push handle to its pixmap <KON 8FEB91>
|
||
_UnlockPixels ; unlock the pixels
|
||
|
||
;----------------------------------------------------------------------------
|
||
; After CopyBits, dispose of the old offscreen graphics world
|
||
|
||
noCopyBits
|
||
move.l a3,-(sp) ; push handle to old GWorld
|
||
_DisposeGWorld ; dispose of it
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Set lock/purge state of new offscreen buffer to the same as old offscreen buffer
|
||
|
||
setState
|
||
move.l newGWorld(a6),a3 ; get pointer to new GWorld
|
||
|
||
; Get here if restoring state of old offscreen buffer after an error (old GWorldPtr is in a3)
|
||
|
||
setStateWithError
|
||
|
||
move.l gwPortPixMap(a3),-(sp) ; push handle to its pixmap <KON 8FEB91>
|
||
move.l state(a6),-(sp) ; push lock/purge state
|
||
_SetPixelsState ; set the state
|
||
|
||
;----------------------------------------------------------------------------
|
||
; If savePort is the old GWorld, set savePort to the new one
|
||
; If saveDevice is the old attached device, set saveDevice to the new attached device
|
||
|
||
move.l offscreenGWorld(a6),a0 ; get pointer to GWorldPtr variable
|
||
move.l (a0),a0 ; get old GWorld
|
||
cmpa.l savePort(a6),a0 ; compare with savePort
|
||
bne.s @notSame ; if not the same, go check the saveDevice
|
||
move.l a3,savePort(a6) ; savePort is old GWorld, replace with new GWorld
|
||
@notSame
|
||
|
||
; Restore current graphics world
|
||
|
||
restoreGWorld
|
||
move.l savePort(a6),-(sp) ; push pointer to saved port
|
||
_SetPort
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Return pointer to new GWorld in offscreenGWorld
|
||
; If got here after an error, a3 contains the old graphics world
|
||
|
||
move.l offscreenGWorld(a6),a0 ; get pointer to GWorldPtr variable
|
||
move.l a3,(a0) ; store pointer to new GWorld in offscreenGWorld variable
|
||
|
||
exit move.w #noErr,MemErr ; assume no error <21Jun89> JCM
|
||
move.l result(a6),d0 ; copy result to d0 <21Jun89> JCM
|
||
bpl.s @0 ; if result is < 0, <21Jun89> JCM
|
||
move.w d0,MemErr ; copy low-word of result to QDErr <21Jun89> JCM
|
||
@0 ; <21Jun89> JCM
|
||
movem.l (sp)+,a2-a4/d5-d7 ; restore regs
|
||
unlk a6 ; get rid of stack frame
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
;----------------------------------------------------------------------------
|
||
; Errors
|
||
|
||
reportError
|
||
ext.l d0 ; convert error to a long
|
||
move.l d0,result(a6) ; report error
|
||
bra.s setStateWithError ; restore state of old offscreen buffer and quit
|
||
|
||
badPixelDepth
|
||
move.l #cDepthErr,result(a6) ; pixel depth invalid
|
||
bra.s exit ; exit
|
||
|
||
purgedError
|
||
move.l #cNoMemErr,result(a6) ; report a Quickdraw memory error
|
||
bra.s setStateWithError ; restore state of old offscreen buffer and quit
|
||
|
||
paramError
|
||
move.l #paramErr,result(a6) ; report a parameter error
|
||
bra.s exit ; and exit
|
||
|
||
; If NewGWorld error fails and the old offscreen buffer was disposed of,
|
||
; reallocate old offscreen buffer, report error, and quit.
|
||
|
||
newGWorldError
|
||
move.l oldBufSize(a6),d1 ; get size of old offscreen buffer
|
||
bmi.s reportError ; if 0, it means old offscreen hasn't been disposed of
|
||
|
||
move d0,d7 ; save error code
|
||
|
||
move.l d1,d0 ; get size of old offscreen buffer in d0
|
||
|
||
move.l gwPortPixMap(a3),a0 ; get pixmap handle
|
||
move.l (a0),a0 ; get pixmap pointer
|
||
tst.b gwPMUseMFTemp(a0) ; were the pixels in temp memory? <07Jul89> JCM
|
||
bz.s @useCurHeap ; no, allocate in current heap <07Jul89> JCM
|
||
_NewHandleCommaTemp ; allocate it in MF heap
|
||
bra.s @shareErr
|
||
@useCurHeap
|
||
_NewHandle ; allocate offscreen buffer (don't initialize it) <07Jul89> JCM
|
||
@shareErr
|
||
bne.s reportError ; if error, report it and quit <07Jul89> JCM
|
||
|
||
@gotMem
|
||
move.l gwPortPixMap(a3),a1 ; get pixmap handle
|
||
move.l (a1),a1 ; get pixmap pointer
|
||
move.l a0,baseAddr(a1) ; store handle to offscreen buffer in baseAddr
|
||
; buffer is not locked so we do not have to set up the baseAddr of the portBits
|
||
|
||
move.w d7,d0 ; restore error code
|
||
bra.s reportError ; report error and quit
|
||
|
||
ENDPROC
|
||
|
||
|
||
SetGWorld PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE SetGWorld (port: CGrafPtr; gdh: GDHandle);
|
||
;
|
||
; Set the current port and device.
|
||
;
|
||
; If port is a GWorldPtr, set the current device to its attached device and ignore gdh.
|
||
; If port is not a GWorldPtr, set the current device to gdh.
|
||
;
|
||
; HIDDEN FEATURES:
|
||
; If port is not a GWorldPtr and gdh is NIL, the current device is set to MainDevice.
|
||
; If port is a GWorldPtr but doesn't have an attached device (should never happen),
|
||
; the current device is set to MainDevice.
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 8 ; size of parameters
|
||
port equ paramSize+4-4 ; LONG, new current port
|
||
gdh equ port-4 ; LONG, new current device
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; Set the current port
|
||
|
||
move.l GrafGlobals(a5),a0 ; get address of Quickdraw Globals
|
||
move.l port(sp),thePort(a0) ; set the current port
|
||
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
|
||
GetGWorldDevice PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION GetGWorldDevice (offscreenGWorld: GWorldPtr): GDHandle;
|
||
;
|
||
; Returns a handle to the attached device to offscreenGWorld.
|
||
; If offscreenGWorld is not a GWorld, returns the current device.
|
||
;
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 4 ; size of parameters
|
||
offscreenDevice equ paramSize+4 ; LONG, handle to attached device
|
||
offscreenGWorld equ offscreenDevice-4 ; LONG, offscreen graphics world
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
clr.l offscreenDevice(sp) ; we don’t have gDevices!
|
||
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
QDDone PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION QDDone (port: GrafPtr): Boolean;
|
||
;
|
||
; Returns true if all pending Quickdraw requests for the given port are completed.
|
||
; Returns false if not.
|
||
;
|
||
; Call PixMapDone to do the job.
|
||
;
|
||
; This function should be called before accessing the pixels directly (e.g.
|
||
; using distorsion algorithm, etc.) or to make sure that the drawing to a given
|
||
; port is finished (animation, etc.)
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 4 ; size of parameters
|
||
result equ paramSize+4 ; BOOLEAN, function result
|
||
port equ result-4 ; LONG, pointer to port
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
move.b #true,result(sp)
|
||
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
|
||
LockPixels PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION LockPixels (pm: PixMapHandle): Boolean;
|
||
;
|
||
; Lock offscreen buffer down, change the handle in baseAddr to a 32-bit
|
||
; pointer to the offscreen buffer, and change the gwPMVersion from pmVersionUnlocked to pmVersionLocked.
|
||
;
|
||
; Don't do anything and return false if handle as been purged.
|
||
; Don't do anything and return true if gwPMVersion is not pmVersionUnlocked.
|
||
;
|
||
; This procedure must be called before drawing to an offscreen world.
|
||
;
|
||
; NOTE: If gwPMVersion is pmVersionLocked, it means LockPixels is being called twice in a row.
|
||
; LockPixels doesn't do anything in this case.
|
||
;
|
||
; The fact that the baseAddr can be locked and unlocked allows Quickdraw
|
||
; to use a relocatable block for offscreen buffers, therefore avoiding heap
|
||
; fragmentation.
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 4 ; size of parameters
|
||
result equ paramSize+4 ; BYTE, result: false if handle is purged
|
||
pm equ result-4 ; LONG, handle to pixmap
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; Assume handle isn't purged
|
||
|
||
move.b #true,result(sp) ; set result to true
|
||
|
||
; Check that PixMap’s version is pmVersionUnlocked.
|
||
; If it's not pmVersionUnlocked, don't do anything and return true
|
||
|
||
move.l pm(sp),a1 ; get handle to pixmap
|
||
move.l (a1),a1 ; get pointer to pixmap
|
||
move gwPMVersion(a1),d0 ; get version
|
||
cmp #pmVersionUnlocked,d0 ; is pixmap unlocked?
|
||
bne.s exit ; no, exit
|
||
|
||
; Get 32-bit pointer to offscreen buffer
|
||
|
||
move.l baseAddr(a1),a0 ; get handle to offscreen buffer
|
||
move.l (a0),d0 ; get master pointer
|
||
_StripAddress ; if 32-bit QD not present, don't use Translate24To32
|
||
|
||
; Check that the offscreen buffer isn't purged
|
||
|
||
tst.l d0 ; is pointer to offscreen buffer = 0?
|
||
bne.s @0 ; no, continue as planned
|
||
move.b #false,result(sp) ; yes, it's purged, return false
|
||
bra.s exit ; and exit
|
||
@0
|
||
|
||
; Store 32-bit pointer in baseAddr
|
||
|
||
move.l d0,baseAddr(a1) ; baseAddr can now be used by 32-bit Quickdraw correctly
|
||
|
||
; Change gwPMVersion to reflect that baseAddr is a 32-bit pointer
|
||
|
||
move #pmVersionLocked,gwPMVersion(a1) ; set version to pmVersionLocked (baseAddr is 32-bit pointer)
|
||
|
||
; Lock down handle to offscreen buffer
|
||
|
||
_HLock ; lock it (a0 contains the handle)
|
||
|
||
; If the pixMap we locked has an associated port, jam in the baseAddr.
|
||
|
||
move.l gwPMPort(a1),d0 ; get the associated port
|
||
bz.s @noPort
|
||
move.l d0,a1 ; point to the port
|
||
move.l (a0),d0 ; get new baseAddr
|
||
_StripAddress
|
||
move.l d0,portBits+baseAddr(a1) ; drop him into place, ready for Quick-drawing <16MAR90 KON>
|
||
@noPort
|
||
|
||
exit rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
|
||
UnlockPixels PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE UnlockPixels (pm: PixMapHandle);
|
||
;
|
||
; If gwPMVersion is pmVersionLocked, change the baseAddr from a pointer to a handle, unlock
|
||
; the handle, and change gwPMVersion to pmVersionUnlocked.
|
||
;
|
||
; If gwPMVersion is not 1, don't do anything.
|
||
;
|
||
; NOTE: If gwPMVersion is pmVersionUnlocked, UnlockPixels is being called twice.
|
||
; UnlockPixels doesn't do anything in this case.
|
||
;
|
||
; This procedure must be called when the application is finished drawing
|
||
; to the offscreen pixmap.
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 4 ; size of parameters
|
||
pm equ paramSize+4-4 ; LONG, handle to pixmap
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; Check that PixMap’s version is pmVersionLocked.
|
||
; If it's not pmVersionLocked, don’t do anything.
|
||
|
||
move.l pm(sp),a1 ; get handle to pixmap
|
||
move.l (a1),a1 ; get pointer to pixmap
|
||
move gwPMVersion(a1),d0 ; get version
|
||
cmp #pmVersionLocked,d0 ; is pixmap locked?
|
||
bne.s exit ; no, exit
|
||
|
||
; If gwPMVersion = pmVersionLocked, convert the baseAddr to a handle and unlock it
|
||
|
||
move.l baseAddr(a1),a0 ; push address of offscreen buffer
|
||
_RecoverHandle ; get handle to offscreen buffer
|
||
_HUnlock ; unlock it
|
||
|
||
; Store handle in baseAddr
|
||
|
||
move.l pm(sp),a1 ; get handle to pixmap
|
||
move.l (a1),a1 ; get pointer to pixmap
|
||
move.l a0,baseAddr(a1) ; store handle to offscreen buffer in baseAddr
|
||
|
||
; Change gwPMVersion to reflect that baseAddr is a handle
|
||
|
||
move #pmVersionUnlocked,gwPMVersion(a1) ; set version to pmVersionUnlocked
|
||
|
||
; If the pixMap we locked has an associated port, jam in the baseAddr.
|
||
|
||
move.l gwPMPort(a1),d0 ; get the associated port <16MAR90 KON>
|
||
bz.s @noPort ; <16MAR90 KON>
|
||
move.l d0,a1 ; point to the port <16MAR90 KON>
|
||
move.l pm(sp),portBits+baseAddr(a1); put the handle to the pixmap back in the port <16MAR90 KON>
|
||
@noPort
|
||
|
||
exit rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
|
||
PortChanged PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE PortChanged (port: CGrafPtr);
|
||
;
|
||
; Called after non-procedural changes are made to a port.
|
||
; This procedure should be called before doing any more drawing.
|
||
;
|
||
; Note: this procedure is useful for Asynchronous Quickdraw
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE PixPatChanged (ppat: PixPatHandle);
|
||
;
|
||
; Called after non-procedural changes are made to a pixel pattern.
|
||
; This procedure should be called before doing any more drawing.
|
||
;
|
||
; Note: this procedure is useful for Asynchronous Quickdraw
|
||
|
||
ENTRY PixPatChanged
|
||
PixPatChanged
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE CTabChanged (cTab: CTabHandle);
|
||
;
|
||
; Called after non-procedural changes are made to a color table.
|
||
; This procedure should be called before doing any more drawing.
|
||
;
|
||
; Note: this procedure is useful for Asynchronous Quickdraw
|
||
|
||
ENTRY CTabChanged
|
||
CTabChanged
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE GDeviceChanged (gdh: GDHandle);
|
||
;
|
||
; Called after non-procedural changes are made to a gDevice
|
||
; This procedure should be called before doing any more drawing.
|
||
;
|
||
; Note: this procedure is useful for Asynchronous Quickdraw
|
||
|
||
ENTRY GDeviceChanged
|
||
GDeviceChanged
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 4 ; size of parameters
|
||
param equ paramSize+4-4 ; LONG
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; doesn't do anything in Synchronous Quickdraw
|
||
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
|
||
AllowPurgePixels PROC ENTRY
|
||
ENTRY NoPurgePixels
|
||
ENTRY GetPixelsState
|
||
ENTRY DisposeScreenBuffer
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE AllowPurgePixels (pm: PixMapHandle);
|
||
;
|
||
; Allow purging of the offscreen buffer by calling HPurge.
|
||
;
|
||
; If gwPMVersion is pmVersionUnlocked, baseAddr is a handle, call HPurge directly.
|
||
; If gwPMVersion is pmVersionLocked, baseAddr is a pointer, get the handle first.
|
||
; If gwPMVersion is not pmVersionLocked or pmVersionUnlocked, don't do anything.
|
||
;
|
||
; NOTE: It is safe to set the purge state of the handle to the offscreen
|
||
; buffer even if the baseAddr contains only the pointer. The reason
|
||
; is that if the baseAddr is a pointer, it means LockPixels has been
|
||
; called and therefore the handle is locked and won't be purged.
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
bsr.s PixelsHandleHelper ; get the handle
|
||
_HPurge
|
||
jmp (a1) ; return
|
||
|
||
|
||
|
||
NoPurgePixels
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE NoPurgePixels (pm: PixMapHandle);
|
||
;
|
||
; Prevents purging of the offscreen buffer by calling HNoPurge.
|
||
;
|
||
; If gwPMVersion is pmVersionUnlocked, baseAddr is a handle, call HNoPurge directly.
|
||
; If gwPMVersion is pmVersionLocked, baseAddr is a pointer, recover the handle first.
|
||
; If gwPMVersion is not pmVersionLocked or pmVersionUnlocked, don't do anything.
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
bsr.s PixelsHandleHelper ; get the handle
|
||
_HNoPurge
|
||
jmp (a1) ; return
|
||
|
||
|
||
|
||
GetPixelsState
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION GetPixelsState (pm: PixMapHandle): LONGINT;
|
||
;
|
||
; Get the state of the offscreen buffer handle by calling HGetState. The result
|
||
; contains two bits: pixelsLockedBit and pixelsPurgeableBit.
|
||
; For convenience, these bits happen to be the same as the lock and purge bit
|
||
; of the Memory Manager.
|
||
;
|
||
; If gwPMVersion is pmVersionUnlocked, the baseAddr is a handle, call HGetState directly.
|
||
; If gwPMVersion is pmVersionLocked, the baseAddr is a pointer, call RecoverHandle first.
|
||
; If gwPMVersion is neither, return 0.
|
||
;
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; Start with a state of 0
|
||
|
||
clr.l 8(sp) ; default result
|
||
|
||
bsr.s PixelsHandleHelper ; get the handle
|
||
bz.s @done ; no handle here!
|
||
_HGetState ; get the state in low byte of d0
|
||
move.b d0,3(sp) ; store state in low byte of result
|
||
@done
|
||
jmp (a1) ; return
|
||
|
||
|
||
|
||
DisposeScreenBuffer
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE DisposeScreenBuffer (offscreenPixMap: PixMapHandle);
|
||
;
|
||
; Dispose the memory allocated for the offscreen pixmap and offscreen buffer.
|
||
; I don't use DisposPixMap because the color table is owned by the device,
|
||
; not the pixmap.
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; Check offscreenPixMap's gwPMVersion. If not pmVersionLocked or pmVersionUnlocked, don't do anything.
|
||
; Get handle to offscreen buffer
|
||
; If gwPMVersion=pmVersionUnlocked, baseAddr is a handle
|
||
; If gwPMVersion=pmVersionLocked, baseAddr is the master pointer
|
||
|
||
move.l 4(sp),-(sp) ;copy return address <6Apr90 KON>
|
||
move.l 4(sp),-(sp) ;copy PixMapHandle <6Apr90 KON>
|
||
bsr.s PixelsHandleHelper ; get the handle, put return address in a1
|
||
bne.s @cont ; DisposeHandle
|
||
|
||
addq #8,sp ;clean up stack <25Jun90 KON>
|
||
jmp (a1) ; <25Jun90 KON>
|
||
@cont
|
||
_DisposHandle ; dispose offscreen buffer
|
||
|
||
move.l (sp)+,a1 ; get return address <6Apr90 KON>
|
||
move.l (sp)+,a0 ; get handle to offscreen PixMap <6Apr90 KON>
|
||
_DisposHandle ; get rid of it <6Apr90 KON>
|
||
jmp (a1) ;<6Apr90 KON>
|
||
|
||
|
||
PixelsHandleHelper
|
||
|
||
; This is a handleburger helper routine which gets the handle to the pixels in a gwPixMap, which
|
||
; may be locked and derefenced at the time.
|
||
;
|
||
; In:
|
||
; (sp) return address
|
||
; 4(sp) caller’s caller
|
||
; 8(sp) GWPixMapHandle
|
||
;
|
||
; Out:
|
||
; CC Z if the pixels are not in a handle, NZ if there is a handle
|
||
; a0 handle to pixels (or NIL, if not in a handle)
|
||
; a1 caller’s caller (return with a jmp (a1))
|
||
;
|
||
; Trashes d0-d2/a0-a1
|
||
|
||
move.l (sp)+,d1 ; keep return address for a rainy day
|
||
move.l (sp)+,d2 ; keep caller’s caller
|
||
move.l (sp)+,d0 ; and a start with the pixmap handle
|
||
bz.s @nothing ; we found nothing at all
|
||
move.l d0,a1
|
||
|
||
move.l (a1),a1 ; get pointer to pixmap
|
||
move.l baseAddr(a1),a0 ; get baseAddr
|
||
|
||
move.w gwPMVersion(a1),d0 ; get gwPMVersion
|
||
cmp.w #pmVersionUnlocked,d0 ; is gwPMVersion an unlocked handle?
|
||
beq.s @gotHandle ; yes, baseAddr is a handle
|
||
cmp.w #pmVersionLocked,d0 ; is gwPMVersion an locked handle?
|
||
bne.s @nothing ; no, don’t do anything
|
||
@gotPointer
|
||
_RecoverHandle ; get the handle
|
||
@gotHandle
|
||
moveq #1,d0 ; set CCs NZ to indicate we found it
|
||
@done
|
||
movea.l d2,a1 ; give the caller his caller
|
||
movem.l d1,-(sp) ; we are done, return preserving condition codes
|
||
rts
|
||
|
||
@nothing
|
||
moveq #0,d0 ; set CCs Z to indicate nothing found
|
||
move.l d0,a0
|
||
bra.s @done
|
||
|
||
ENDPROC
|
||
|
||
|
||
SetPixelsState PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; PROCEDURE SetPixelsState (pm: PixMapHandle; flags: LONGINT);
|
||
;
|
||
; Set the state of the offscreen buffer handle by calling LockPixels/UnlockPixels
|
||
; and AllowPurgePixels/NoPurgePixels.
|
||
;
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 8 ; size of parameters
|
||
pm equ paramSize+4-4 ; LONG, handle to pixmap
|
||
gwFlags equ pm-4 ; LONG, flags
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
; Check pixelsPurgeableBit and call AllowPurgePixels or NoPurgePixels
|
||
|
||
move.l gwFlags(sp),d0 ; get the flags
|
||
btst.l #pixelsPurgeableBit,d0 ; is pixelsPurgeableBit set?
|
||
bne.s allowPurge ; yes, call AllowPurgePixels
|
||
|
||
move.l pm(sp),-(sp) ; no, call NoPurgePixels
|
||
_NoPurgePixels
|
||
bra.s checkLock
|
||
|
||
allowPurge
|
||
move.l pm(sp),-(sp) ; call AllowPurgePixels
|
||
_AllowPurgePixels
|
||
|
||
; Check pixelsLockedBit and call LockPixels or UnlockPixels
|
||
|
||
checkLock
|
||
move.l gwFlags(sp),d0 ; get the flags
|
||
btst.l #pixelsLockedBit,d0 ; is pixelsLockedBit set?
|
||
bne.s lockIt ; yes, call LockPixels
|
||
|
||
move.l pm(sp),-(sp) ; no, call UnlockPixels
|
||
_UnlockPixels
|
||
bra.s exit
|
||
|
||
lockIt
|
||
move.l pm(sp),a0 ; get PixMapHandle
|
||
clr.b -(sp) ; room for Boolean result
|
||
move.l a0,-(sp) ; push PixMapHandle
|
||
_LockPixels ; call LockPixels
|
||
move.b (sp)+,d0 ; ignore result
|
||
|
||
exit
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
GetPixBaseAddr PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION GetPixBaseAddr (pm: PixMapHandle): Ptr;
|
||
;
|
||
; Make sure that Asynchronous Quickdraw is done and get the 32-bit pointer to
|
||
; the offscreen buffer.
|
||
;
|
||
; If gwPMVersion is PixMapVers4, the baseAddr is a 32-bit pointer, just return it.
|
||
; If gwPMVersion is pmVersionUnlocked, the baseAddr is a handle, get the 24-bit pointer and clean it.
|
||
; If gwPMVersion is pmVersionLocked, the baseAddr is a clean 24-bit pointer, just return it.
|
||
; If gwPMVersion is PixMapVers0,
|
||
; if the baseAddr is the same as one of the screens in the devicelist then return it
|
||
; else clean it first.
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 4 ; size of parameters
|
||
bufResult equ paramSize+4 ; LONG, result
|
||
pm equ bufResult-4 ; LONG, handle to pixmap
|
||
|
||
; Initialize bufPtr to baseAddr (assume gwPMVersion is not pmVersionUnlocked).
|
||
|
||
move.l pm(sp),a1 ; get handle to pixmap
|
||
move.l (a1),a1 ; get pointer to pixmap
|
||
move.l baseAddr(a1),a0 ; get baseAddr
|
||
move.l a0,bufResult(sp) ; store in result
|
||
|
||
; Check PixMap's gwPMVersion.
|
||
|
||
move.w gwPMVersion(a1),d0 ; get gwPMVersion
|
||
btst #pmVersionHandleBit,d0 ; is it a handle?
|
||
beq.s exit ; no, we're done
|
||
|
||
; If gwPMVersion = pmVersionUnlocked, baseAddr is a handle, get the master pointer
|
||
; and translate it to a 32-bit pointer.
|
||
|
||
move.l (a0),d0 ; get master pointer
|
||
_StripAddress ; if 32-bit QD not present, don't use Translate24To32
|
||
move.l d0,bufResult(sp) ; store it in result
|
||
|
||
exit rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
|
||
|
||
Pixmap32Bit PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION Pixmap32Bit (pm: PixMapHandle): boolean;
|
||
;
|
||
;
|
||
; If gwPMVersion is PixMapVers4, the baseAddr is a 32-bit pointer, return true.
|
||
; If gwPMVersion is pmVersionUnlocked, the baseAddr is a handle, return false.
|
||
; If gwPMVersion is pmVersionLocked, the baseAddr is a 24-bit pointer, return false.
|
||
; If gwPMVersion is PixMapVers0,
|
||
; if the baseAddr is the same as a devicelist screen, then return true (for now)
|
||
; else return false.
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 4 ; size of parameters
|
||
bufResult equ paramSize+4 ; boolean, result
|
||
pm equ bufResult-4 ; LONG, handle to pixmap
|
||
|
||
|
||
; Initialize result to false (assume gwPMVersion is not PixMapVers4 or a screen).
|
||
|
||
clr.w bufResult(sp) ; assume return false
|
||
|
||
exit rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
NewScreenBuffer PROC ENTRY
|
||
ENTRY NewTempScreenBuffer
|
||
ENTRY NewGWBuffer
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; A6 offsets of parameters after link:
|
||
;
|
||
paramSize equ 14 ; size of parameters
|
||
result equ paramSize+8 ; WORD, OSErr
|
||
boundsRect equ result-4 ; LONG, address of global Rectangle
|
||
purgeable equ boundsRect-2 ; BOOLEAN, purgeable pixels flag <14Jul89> JCM
|
||
gdhP equ purgeable-4 ; LONG, address of GDHandle variable <14Jul89> JCM
|
||
offscreenPMP equ gdhP-4 ; LONG, address of PixMapHandle variable
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; A6 offsets of local variables after link:
|
||
;
|
||
|
||
bytesPerRow equ -2 ; WORD, rowBytes of offscreen pixmap
|
||
offscreenBufH equ bytesPerRow-4 ; LONG, handle to the offscreen buffer
|
||
offscreenPixMap equ offscreenBufH-4 ; LONG, handle to the offscreen pixmap
|
||
pixmapBounds equ offscreenPixMap-8 ; Rect, rectangle describing pixmap bounds
|
||
localRect equ pixmapBounds-8 ; Rect, localized version of rect passed in <10>
|
||
varSize equ localRect ; size of local variables <14Jul89> JCM
|
||
|
||
;----------------------------------------------------------------------------
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION NewScreenBuffer (globalRect: Rect; purgeable: BOOLEAN; <14Jul89> JCM
|
||
; VAR gdh: GDHandle; VAR offscreenPixMap: PixMapHandle): OSErr;
|
||
;
|
||
; Creates an offscreen pixmap and an offscreen buffer, using globalRect as a global
|
||
; rectangle in screen space and finding the deepest device that intersects that
|
||
; rectangle. The device is returned in gdh, the offscreen PixMap is created
|
||
; according to the characteristics of the device (pixel depth, color table, etc.).
|
||
; The color table is shared with the device.
|
||
|
||
link a6,#varSize ; allocate local variables <7> csd
|
||
movem.l d3-d7/a2-a4,-(sp) ; save regs <7> csd
|
||
moveq #0,d5 ; MF temp mem selector = 0 (don't use MF temp mem) <14Jul89> JCM
|
||
bra.s CommonScreenBuffer ; branch to common code
|
||
|
||
;---------------------------------------------------------------------------- <14Jul89> JCM
|
||
; <14Jul89> JCM
|
||
; FUNCTION NewTempScreenBuffer (globalRect: Rect; purgeable: BOOLEAN; <14Jul89> JCM
|
||
; VAR gdh: GDHandle; VAR offscreenPixMap: PixMapHandle): OSErr; <14Jul89> JCM
|
||
; <14Jul89> JCM
|
||
; Same as NewScreenBuffer but allocates the pixels in MultiFinder temporary memory <14Jul89> JCM
|
||
|
||
NewTempScreenBuffer ; <14Jul89> JCM
|
||
link a6,#varSize ; allocate local variables <7> csd
|
||
movem.l d3-d7/a2-a4,-(sp) ; save regs <7> csd
|
||
moveq #1,d5 ; MF temp mem selector = 1 (use MF temp mem) <14Jul89> JCM
|
||
|
||
CommonScreenBuffer
|
||
moveq #0,d7
|
||
moveq #0,d6
|
||
lea localRect(a6),a3 ; use the localRect from here
|
||
bra.s CommonBuffer ; enter buffer code after link & register save <7> csd
|
||
|
||
; FUNCTION NewGWBuffer (globalRect: Rect; purgeable: BOOLEAN;
|
||
; VAR gdh: GDHandle; VAR offscreenPixMap: PixMapHandle): OSErr
|
||
|
||
; NewGWBuffer is shared by NewScreenBuffer and NewGWorld
|
||
; It has the same parameters as NewScreenBuffer, except for:
|
||
|
||
; 1) D5.B contains 0 for normal memory, 1 for MF temp. memory
|
||
; 2) D7.W contains 0 to get depth from screen, non-zero to use specific depth
|
||
; 3) d6.L contains the number of extra pixels for alignment (31 for NewGWorld, 0 for NewScreenBuffer)
|
||
; 4) A3 contains a place to put the localRect (for use as a portRect later)
|
||
|
||
NewGWBuffer
|
||
|
||
link a6,#varSize ; allocate local variables
|
||
movem.l d3-d7/a2-a4,-(sp) ; save regs
|
||
|
||
CommonBuffer ; <7> csd
|
||
move.l boundsRect(a6),a2
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Initialize the function result to no error. Optimistically assume that
|
||
; everything will go fine.
|
||
|
||
moveq #noErr,d3 ; flag a successful operation,
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Initialize all offscreen local variables to zero.
|
||
; If an error happens during this function, we deallocate the memory for
|
||
; all allocated offscreen variables.
|
||
|
||
clr.l offscreenBufH(a6) ; handle to offscreen buffer
|
||
clr.l offscreenPixMap(a6) ; handle to offscreen pixmap
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Check that the boundsRect is not an empty rectangle.
|
||
; If it is empty, don't do anything.
|
||
;
|
||
clr.b -(sp) ; leave room for Boolean result <25JUN90 KON>
|
||
move.l boundsRect(a6),-(sp) ; push address of rectangle on the stack <25JUN90 KON>
|
||
_EmptyRect ; check if rectangle is empty or not <25JUN90 KON>
|
||
move.b (sp)+,d0 ; look at the result <25JUN90 KON>
|
||
bne paramError ; if true, boundsRect is empty, exit with error <25JUN90 KON>
|
||
|
||
;-------------------------------------------------------------------------
|
||
; For maximum efficiency when copying offscreen pixmap to screen, try
|
||
; to match the pixel alignment of the offscreen pixmap to the pixel
|
||
; alignment of the portion of screen space described by boundsRect.
|
||
|
||
computeAlignment
|
||
|
||
move.l topLeft(a2),topLeft(a3)
|
||
move.l botRight(a2),botRight(a3)
|
||
|
||
move.l a3,a2 ; and use the localRect from now on <10>
|
||
|
||
; Convert localRect to local coordinates (topLeft = 0, 0) <10>
|
||
|
||
tst.w d7 ; don’t convert bounds to local if depth is specified
|
||
bnz.s @noLocalizing
|
||
|
||
move.w left(a2),d0 ; compute boundsRect->right - boundsRect->left <10>
|
||
sub.w d0,right(a2) ; store in localRect.right <10>
|
||
move.w top(a2),d0 ; compute boundsRect->bottom - boundsRect->top <10>
|
||
sub.w d0,bottom(a2) ; store in localRect.bottom <10>
|
||
clr.l topLeft(a2) ; set localRect.top and localRect.left to 0 <10>
|
||
|
||
@noLocalizing
|
||
|
||
; Change the left coordinate of the pixmap bounds so that the buffer will be aligned.
|
||
; To align, just clear out the low bits.
|
||
|
||
move.l topLeft(a2),pixmapBounds+topLeft(a6) ; pixmapBounds.top = localRect.top
|
||
move.l botRight(a2),pixmapBounds+botRight(a6) ; bottom and right coordinates unchanged
|
||
|
||
tst.w d7 ; don’t align if depth is specified
|
||
bnz.s @noAligning
|
||
|
||
and.w #~$1F,pixmapBounds+left(a6) ; align the buffer
|
||
@noAligning
|
||
|
||
; Bug fix:
|
||
; If d6 contains 0, that means that this pixmap is not going to be realigned.
|
||
; It also means that the rowBytes computation is not taking into account the full width
|
||
; of the buffer, because it assumes that the localRect width plus the slop is enough to cover
|
||
; any future realignment. Because of this, we load a2 with pixMapBounds(a6), if d6 is 0.
|
||
|
||
tst.l d6 ; is this going to be realigned
|
||
bnz.s @useLocalRect ; yes, use the localRect plus the 31 bits of slop
|
||
lea pixmapBounds(a6),a2 ; no, use pixmapBounds, but no need for any slop
|
||
@useLocalRect
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Allocate the actual offscreen buffer.
|
||
; rowBytes is computed as the smallest number of longs containing one line of pixel + 31 bits,
|
||
; converted to bytes:
|
||
; (((localRect.right - localRect.left) * pixelSize + 31 + 31) / 32) * 4
|
||
;
|
||
; NOTE 1: Adding 31 bits gives us some leg room if we want to realign the pixmap in UpdateGWorld.
|
||
; The additional 31 bits are to force a round-up top the next long (as usual).
|
||
; NOTE 2: localRect is used instead of pixmapBounds because rowBytes is computed independently
|
||
; of the current alignment but for all possible alignments.
|
||
;
|
||
; size of the buffer is:
|
||
; rowBytes * (pixmapBounds.bottom - pixmapBounds.top)
|
||
|
||
allocateBuffer
|
||
move.w right(a2),d0 ; get right coordinate
|
||
sub.w left(a2),d0 ; compute number of pixels per line
|
||
ext.l d0 ; convert to long
|
||
add.l #31,d0 ; add 31 bits
|
||
add.l d6,d0 ; add more bits if necessary
|
||
lsr.l #5,d0 ; convert bits to longs
|
||
lsl.w #2,d0 ; convert longs to bytes
|
||
move.w d0,bytesPerRow(a6) ; save # of bytes in a row
|
||
|
||
move.w bottom(a2),d1 ; compute height of rectangle
|
||
sub.w top(a2),d1 ; bottom-top
|
||
mulu.w d1,d0 ; compute height * rowBytes
|
||
|
||
tst.b d5 ; use MF temp memory? <14Jul89> JCM
|
||
beq.s @useCurHeap ; no, allocate in current heap <07Jul89> JCM
|
||
_NewHandleCommaTemp ; allocate in MF heap
|
||
bra.s @joinUs
|
||
@useCurHeap
|
||
_NewHandle ; allocate offscreen buffer (don’t initialize it) <07Jul89> JCM
|
||
@joinUs
|
||
bne.s reportError ; if Memory Manager error, report it and quit <07Jul89> JCM
|
||
|
||
@gotMem
|
||
move.l a0,offscreenBufH(a6) ; save handle to offscreen buffer
|
||
|
||
_MoveHHi ; move the buffer as high as possible in memory
|
||
|
||
; If the purgeable flag is set, make the offscreen buffer purgeable <14Jul89> JCM
|
||
|
||
tst.b purgeable(a6) ; is purgeable flag set? <14Jul89> JCM
|
||
beq.s @0 ; no, leave as is
|
||
_HPurge ; yes, make it purgeable
|
||
@0
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Create the offscreen PixMap.
|
||
; The baseAddr is a handle to the offscreen buffer.
|
||
; IMPORTANT: the gwPMVersion field is set to pmVersionUnlocked.
|
||
; gwPMVersion = pmVersionUnlocked means that the baseAddr is a handle.
|
||
; gwPMVersion = pmVersionLocked means that the baseAddr is a 32-bit pointer.
|
||
|
||
createPixMap
|
||
moveq #gwPMSize,d0 ; get size of PixMap structure
|
||
_NewHandle clear ; allocate the handle
|
||
bne.s reportError ; if Memory Manager error, report it and quit
|
||
|
||
move.l a0,offscreenPixMap(a6) ; save it
|
||
move.l (a0),a1 ; a1 = pixmap pointer
|
||
|
||
; Start filling out the fields of the pixmap
|
||
|
||
move.l offscreenBufH(a6),baseAddr(a1) ; store HANDLE to offscreen buffer in pixmap
|
||
move bytesPerRow(a6),rowBytes(a1) ; store rowBytes and pixmap flag in pixmap
|
||
move.l pixmapBounds+topLeft(a6),bounds+topLeft(a1) ; copy pixmapBounds to pixmap's bounds
|
||
move.l pixmapBounds+botRight(a6),bounds+botRight(a1)
|
||
move #pmVersionUnlocked,gwPMVersion(a1) ; IMPORTANT: set pixmap's version to version 2 (baseAddr is a handle)
|
||
move.b d5,gwPMUseMFTemp(a1) ; remember if we used temp. memory
|
||
|
||
;-------------------------------------------------------------------------
|
||
; Store the offscreen PixMap and museDevice in the offscreenPixMap and gdh VARs
|
||
|
||
move.l offscreenPMP(a6),a0 ; get address of PixMapHandle variable
|
||
move.l offscreenPixMap(a6),(a0) ; store handle to offscreen PixMap in it
|
||
move.l gdhP(a6),a0 ; get address of GDHandle variable
|
||
clr.l (a0) ; store handle to museDevice in it
|
||
|
||
;-------------------------------------------------------------------------
|
||
; We're done. Return error code and put a copy of it in low-memory MemErr.
|
||
|
||
goHome
|
||
move d3,result(a6) ; get error code in to return
|
||
move d3,MemErr
|
||
movem.l (sp)+,d3-d7/a2-a4 ; restore regs
|
||
unlk a6 ; get rid of stack frame
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
;-------------------------------------------------------------------------
|
||
; When an error occurs, all allocated memory is freed and an error code
|
||
; is returned.
|
||
|
||
paramError
|
||
move #paramErr,d3 ; one of the parameters is invalid
|
||
bra.s disposOffscreenHandles ; release memory and exit
|
||
|
||
reportError
|
||
move.w d0,d3 ; directly report Memory Manager error
|
||
|
||
; Dispose of all allocated memory (handle is allocated when non zero)
|
||
|
||
disposOffscreenHandles
|
||
|
||
move.l offscreenBufH(a6),a0 ; get handle to offscreen buffer
|
||
_DisposHandle ; dispose it
|
||
move.l offscreenPixMap(a6),a0 ; get handle to offscreen pixmap
|
||
_DisposHandle ; dispose it
|
||
bra.s goHome ; exit
|
||
|
||
ENDPROC
|
||
|
||
|
||
OffscreenVersion PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION OffscreenVersion (): LONGINT;
|
||
;
|
||
; Returns the version number of the current version of the Quickdraw extensions.
|
||
; The first version doesn't have OffscreenVersion implemented and will therefore
|
||
; return a paramErr.
|
||
|
||
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 0 ; size of parameters
|
||
version equ paramSize+4 ; LONG, result
|
||
|
||
move.l #OffscreenVersNum,version(sp) ; return version number
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
GetGWorldPixMap PROC ENTRY
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; FUNCTION GetGWorldPixMap (gw: GWorldPtr): PixMapHandle;
|
||
;
|
||
; Given a GWorld, get the associated PixMap.
|
||
;
|
||
;----------------------------------------------------------------------------
|
||
;
|
||
; Stack offsets of parameters
|
||
;
|
||
paramSize equ 4 ; size of parameters
|
||
pmResult equ paramSize+4 ; LONG, result (handle to PixMap)
|
||
gw equ pmResult-4 ; LONG, pointer to GWorld
|
||
|
||
; The PixMap is right there in the port.
|
||
|
||
move.l gw(sp),a0
|
||
move.l gwPortPixMap(a0),pmResult(sp)
|
||
|
||
rtd_a0 paramSize ; get rid of parameters and return to caller
|
||
|
||
ENDPROC
|
||
|
||
|
||
NewHandleCommaTemp PROC ENTRY
|
||
|
||
; NewHandleCommaTemp has the same interfaces as NewHandle, but it gets memory from
|
||
; MF temp. memory. If MultiFinder is not running, returns a nil handle and cTempMemErr.
|
||
|
||
OSDispatchTrapNum EQU $8F ; _OSDispatch trap number
|
||
UnImplTrapNum EQU $9F ; _Unimplemented trap number
|
||
|
||
movem.l a1/d1-d2,-(sp) ; save work registers
|
||
move.l d0,d1 ; copy requested size
|
||
|
||
move.w #OSDispatchTrapNum,d0 ; _OSDispatch trap number
|
||
_GetTrapAddress newTool ; address of _OSDispatch
|
||
move.l a0,a1 ; save address
|
||
|
||
move.w #UnImplTrapNum, D0 ; _Unimplemented trap number
|
||
_GetTrapAddress newTool ; address of _Unimplemented trap
|
||
|
||
cmp.l a0,a1 ; is _OSDispatch implemented (i.e. MultiFinder running)?
|
||
bne.s @MFExists ; yes, go try for it
|
||
move.l #0,a0 ; return nil handle
|
||
move.w #cTempMemErr,d0 ; return error
|
||
bra.s @done
|
||
|
||
@MFExists
|
||
subq.l #4,sp ; room for result
|
||
move.l d1,-(sp) ; ask for it
|
||
pea MemErr ; var result code
|
||
_MFTempNewHandle
|
||
move.l (sp)+,a0 ; get result
|
||
move.w MemErr,d0 ; get result code
|
||
|
||
@done
|
||
movem.l (sp)+,a1/d1-d2 ; restore work registers
|
||
rts
|
||
|
||
ENDPROC
|