mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-21 18:35:32 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
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
|