supermario/base/SuperMarioProj.1994-02-09/QuickDraw/Classic/ClassicGWorld.a
2019-06-29 23:17:50 +08:00

2258 lines
84 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; 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 dont 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 doesnt 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 ; dont 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, dont 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 dont 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 ports 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 ports 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 dont 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 PixMaps 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 PixMaps version is pmVersionLocked.
; If it's not pmVersionLocked, dont 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) callers 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 callers 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 callers 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, dont 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 ; dont 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 ; dont 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 (dont 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