mac-rom/QuickDraw/PaletteMgr.a
Elliot Nunn b295a57713 Clean QuickDraw lurkers
Only three monolithic chunks of code to go!
2017-10-09 15:46:40 +08:00

6029 lines
228 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;__________________________________________________________________________________________________
; File: PaletteMgr.a
;
; Contains: The Palette Manager
;
; Written by: Art Cabral and David Van Brink and lots of others
;
; Copyright: © 1987-1993 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM11> 10/28/93 SAH Rolled out change SM9 because it brought out bugs in the font
; manager. Rolled out change 14 because it caused the bug that
; caused change SM9. Both of these are correct changes, we just
; need to take them out until FlushFonts really flushes ALL the
; fonts (for all processes)...
; <SM10> 10-19-93 jmp Removed the ctSeed whacking (Kon explained the error of my
; ways). WeÕll have to come up with some other method to fix
; dimming.
; <SM9> 9/20/93 SAH Fixed a bug in ActivatePalette where it would always mark black
; or white tolerant entries as handled. It really needed to make
; sure they weren't explicit as well.
; <SM8> 9/13/93 SAM Added a "code" to PMExit to call _TrashProcess (HeapUtilities).
; <SM7> 08-03-93 jmp Changed the SetDepth code so that the MenuBar gets redrawn first
; after a depth switch. This is the way the pre-System7 Monitors
; 'cdev' did things. And it looks much nicer.
; <SM6> 1/13/93 kc Export ReleaseList so that we can vectorize it.
; <SM5> 12/11/92 HI Changes the HasLayers conditional to 1 from 0. SuperMario ROM
; has LayerMgr. Wrong conditional produced the wrong code in
; SetDepth which ends up calling PaintOne/PaintBehind sequence
; instead of RedrawAll. This fixes the problem of balloon help
; update problem when changing bit depths within Monitors CP.
; (Hoon Im)
; <SM4> 5/21/92 kc Change the name of Allocate to PMAllocate to avoid name conflict
; with the glue.
; <SM3> 5/4/92 FM fix typo
; <SM2> 5/4/92 FM Roll in changes from PatchIICiRom.a file that were "lost" in the
; review processÉSave and restore window list in PMgrExit. Also
; zero out d3/d4 in resize palette so that the high word won
; <45> 7/10/91 JSM Remove obsolete SysVers conditional and obsolete ExitToShell
; patch.
;
; <44> 2/26/91 DFH csd,WS#910226a: Fixed bug in ptchPMgrExit where it assumed that
; graphics has been initialized. Bug introduced by change <43>.
; <43> 1/18/91 dvb Don't restore color environment if it hasn't been changed.
; <42> 1/3/91 VL (ngk) Replaced undefined HasLayerMgr conditional with HasLayers.
; (HasLayerMgr is actually set for system build. However, since
; this file is included by files like PatchIIROM.a which may not
; be used for system build, the conditional never gets set.) Also
; used new LayerMgr call RedrawAll to refresh screen in SetDepth.
; <41> 12/14/90 SMC Changed DisposeAppPalettes to use ApplZone->bklim to determine
; if palette is in the application heap. With DFH.
; <40> 12/14/90 jmp SetDepth had a problem where the port was NOT being preserved,
; so we (jmp & smc) moved the port preserving code to come just
; before the InitGDevice call. Also, for Layer Manager support,
; we changed the PaintOne/PaintOne sequence to be a
; PaintOne/PaintBehind sequence per dba & vl.
; <39> 10/30/90 DC ngk - Add a check for the basic four-bit grayscale clut in
; CheckColors
; <38> 10/24/90 DC VL - Fix CheckColors to use bit 2 of the value field as an
; inhibit bit instead of an enable bit
; <37> 10/12/90 jmp I put SetDepth back the way it was; it still doesnÕt work right,
; but I donÕt have time to mess with it now. Will look into it
; later. Basic problem: thePort is trashed. Bumped version back to
; 2.0.2.
; <36> 10/10/90 jmp Changed SetDepth call to match Monitors; also, updated
; PMgrVersion to 2.0.3 so Monitors could tell when to use SetDepth
; or not.
; <35> 9/23/90 DC csd Fix bug in GetGray when input GDevice is NULL
; <34> 9/17/90 BG Removed <21>. 040s are now behaving more reliably.
; <33> 9/15/90 DC added GetGray and put some quick elimination tests into
; CheckColors
; <32> 8/22/90 DC Added inhibit bit to CheckColors and check for individual max
; tolerance
; <31> 8/20/90 dvb Remove DrawGrayishString
; <30> 8/17/90 gbm The name of grayishTextCopy has changed to grayishTextOr
; <29> 8/7/90 gbm moving SysColors into InitPalettes will get rid of some
; assembler warnings
; <28> 8/3/90 dvb Make setdepth redraw _all_ layers.
; <27> 7/20/90 gbm Warning hunt.
; <26> 7/19/90 DVB Fix stack error in DrawGrayishString
; <24> 7/17/90 DVB Use GetFontInfo instead of FMSwapFont
; <23> 7/14/90 DVB Add "DrawGrayishString"
; <22> 6/28/90 DVB Fix CheckColors
; <21> 6/28/90 BG Added EclipseNOPs to fix temporary flakey 040 problems.
; <20> 6/27/90 DVB Add "CheckColors" dispatch
; <19> 6/19/90 DVB Do Gestalt checking for process mgr, implement pmWhite and
; pmBlack
; <18> 6/15/90 DVB Make ciPrivate always a word, to free up an entry word.
; Get/SetPaletteUpdates. Don't fix color environment on background
; quit.
; <17> 5/17/90 KON Sizes are a word, rather than a long when comparing palette
; sizes in resize palette.
; <16> 3/30/90 DVB Bump PaletteVersion
; <15> 3/29/90 DVB Make "WhatPal" nice, and available to layer mgr.
; <14> 3/2/90 DVB Fix explicit+tolerant+inhibit.
; <13> 2/23/90 DVB Don't clear windowlist in PMgrExit.
; <12> 2/21/90 JS SetDepth also takes a mode...
; <11> 2/15/90 DVB Change SetDepth's return to an OSErr
; <10> 2/14/90 DVB Correct SetDepth's trashage of registers
; <9> 2/5/90 DVB Back-roll the 605 InitGDevice to the BBS master, here. <DVB>
; <8> 1/29/90 DVB Unhilite menu during "SetDepth" call, add rounded corners on
; setdepth
; <7> 1/18/90 DVB Undo last changes
; <6> 1/18/90 DVB Make work with cleaned-up PaletteEqu.a
; <5> 1/17/90 DVB Add PMgr version call, fix unreserveDevices
; <4> 1/12/90 DVB Remove automatic tailpatch to ExitToShell, added SetDepth and
; HasDepth calls.
; <3> 1/2/90 DVB Remove a reference to SysVers, in favor of ForROM
; <1.9> 7/14/89 BAL FOR Aurora: Changed some left shifts to some adds as per gary
; <¥2.0> 7/14/89 BAL For Aurora: Final CQD
; <1.8> 7/13/89 BAL Really, dvb, 1.8, fixed SetPal(-1,nil,x).
; <1.7> 7/8/89 BAL Modified PMgrDispatch to skip args of yet-uninvented calls.
; <1.6> 6/28/89 BAL really dvb - ciRGB is valid except for animated entries, where
; <¥1.5> 6/10/89 CEL Moved Private.a QuickDraw Equates into proper QuickDraw private
; file (colorequ.a), got rid of QuickDraw nFiles dependencies and
; fixed up necessary filesÉ
; <¥1.4> 5/29/89 BAL Blasting in 32-Bit QuickDraw version 1.0 Final
; 3/30/87 JTC Daisy chain the IAZInit routine properly.
; 3/27/87 EHB window manager calls added
; 3/27/87 AWC interface changed to support window manager
; 2/2/87 AWC new this date
;
; To Do: Make tolerant entries go faster by replacing color2index call with linear search!
; On activatepalette, activate every window from back to front, for total satisfaction!
; Don't forget about InitApp and CleanupApp
; Let DeltaRGB be (R+G+B)/3 or >>2
; Get an invalmenubar!
; PMDithered
; Question: should we call "CheckForProcessMgr" for a ROM version?
; ( instead of calling Gestalt )
; !! Roll in change 14 to the PatchciROM.a file...it was a single BMI.s
; near the top of Correlate.
;
;__________________________________________________________________________________________________
XPalettes PROC EXPORT ; dummy procedure; return to globals AWC.PB457
ENDPROC ; AWC.PB457
IF (&TYPE('ROMPaletteMgr') = 'UNDEFINED') THEN
IF ForROM THEN ; <1.7>
ROMPaletteMgr EQU 1 ; <1.7>
ELSE ; <1.7>
ROMPaletteMgr EQU 0
ENDIF ; <1.7>
ENDIF
IF NOT (ForROM) THEN
JacksonPollack EQU 0
PatchGetCTable EQU 1
PatchInitGDevice EQU 1
HasLayers EQU 1
ELSE ; ForRom
HasLayers EQU 1 ; ROM now has the LayerMgr. <SM5>
ENDIF ; Not ForRom
INCLUDE 'Processes.a'
INCLUDE 'GestaltEqu.a'
INCLUDE 'LayerEqu.a'
AppPalette Equ $DCC ; low memory global for layer palette AWC.PB457
UpdateMask Equ $E000 ; bits used to record update flags in pmPrivate AWC.PB457
AllUpdates Equ $C000 ; combination of CForeBit and CBackBIt AWC.PB457
plttUpdates Equ $0002 ; value passed to SetPalette [short] AWC.PB457
;ctTolBit EQU 5 ; bit in value field saying "I've been yanked"
;ctTolVal EQU $2000
;ctScatterBit EQU 4 ; bit in value field saying "scatter me" <dvb3>
;ctMatchBit EQU 3 ; bit in value field saying "been checked"
;ctScatterVal EQU $1000 ; word-write equivalent of ctScatterBit <dvb3>
;ctReserveBit EQU 6
;ctReserveVal EQU $4000
PMgrVersNum EQU $0203 ; Version number (VVss: version subversion)
;-----------------------------------------------------------
; Let's talk about PMgrVersNum --
;
; The first version with the PMgrVersion call was $0201. This was released
; as 6.0.5.
;
; Version $0202 adds:
; Dispatch #5: WhatPal
; GetPaletteUpdates, SetPaletteUpdates, pmWhite, pmBlack, CheckColors
;-----------------------------------------------------------
; Here is what is left of the Patch Collator stuff. The Palette Manager routines have never
; been patches to the ROM - they were never in the original ROM, so there was nothing to
; patch. This is all there is. The window manager patches are shown below and are marked
; near the routine with another patch signal. To find one, double click on the Patch Name
; and search for that (Command-H under MPW 2.0).
;
; File Date Patch# PMgr Routines Trap#
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (InitPalettes) $AA90
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (NewPalette) $AA91
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (GetNewPalette) $AA92
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (DisposePalette) $AA93
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (ActivatePalette) $AA94
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (SetPalette) $AA95
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (GetPalette) $AA96
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (PmForeColor) $AA97
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (PmBackColor) $AA98
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (AnimateEntry) $AA99
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (AnimatePalette) $AA9A
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (GetEntryColor) $AA9B
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (SetEntryColor) $AA9C
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (GetEntryUsage) $AA9D
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (SetEntryUsage) $AA9E
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (CTab2Palette) $AA9F
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (Palette2CTab) $AAA0
;AppleSystemPatch PaletteMgr.a 22Jul87 #PB222 (CopyPalette) $AAA1
;
; Fix File Date Patch# Fixed Routines Patch Routine Name
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (RGBForeColor) (RGBForeColor)
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (RGBBackColor) (RGBBackColor)
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB506 (InitMenus) (myInitMenus)
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (NewCWindow) (myNewCWindow)
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (NewWindow) (myNewWindow)
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (HiliteWindow) (myHiliteWindow)
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (MoveWindow) (myMoveWindow)
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (SizeWindow) (mySizeWindow)
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (CloseWindow) (myClose)
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (ShowHide) (myShowHide)
;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (MyExit) (myExit)
;
; Another routine which must be included for proper Palette Manager operation is
; GetNewCWindow which is patched in PatchIIROM.a
FlushPalettes PROC EXPORT ; THIEVED FROM THE MEMORY MGR
;-----------------------------------------------------------------------
; Call DisposePalette for all palettes in the app heap.
;
; Registers: D0-D2/A0-A1
; Called by vIAZInit.
;----------------------------------------------------------------------
IMPORT AppZoneAddr
MOVEM.L A2-A3/D3,-(SP) ; save work registers
MOVE.L PMgrHandle,A2 ; get paletteMgr handle
CMP.L MinusOne,A2 ; is it there?
BEQ.S @DONE ; => no, just return
MOVE.L (A2),A1 ; point to data structure
MOVE.L PListHandle(A1),A0 ; get handle to palette list
_HLock ; and lock it down
MOVE.L (A0),A3 ; point to palette list
Move APalettes(A1),D3 ; get number of active handles
Beq.s @NoPals ; no friends => go home
Add FreeSpaces(A1),D3 ; calculate total number of entries
BRA.S @FindEnd ; => check for no entries
@FindLoop Move.L PaletteRef(A3),D1 ; get first entry
BEQ.S @FindNext ; => no palette in entry
MOVE.L D1,D0 ; and get for routine
JSR AppZoneAddr ; in application area (or zero)? <SM30 BT>
BNE.S @FindNext ; => not in app heap
MOVE.L D1,-(SP) ; push palette handle
DC.W $AA93 ; _DisposePalette ; and dispose it in place
@FindNext AddQ #PLstEntrySz,A3 ; bump to the next entry
@FindEnd DBra D3,@FindLoop ; repeat for all spaces
@NoPals MOVE.L (A2),A1 ; point to palette stuff
MOVE.L PListHandle(A1),A0 ; get handle to palette list
_HUnlock ; and unlock it
@DONE MOVEM.L (SP)+,A2-A3/D3 ; restore work registers
RTS
;---------------------------------------------------
;
; PROCEDURE ActivatePalette(dstWindow: WindowPtr); INLINE $AA94;
;
; ActivatePalette does what is documented in IM5. UpdatePalette is an internal
; routine that is passed a Palette handle, instead of a window.
PROC
EXPORT ActivatePalette,UpdatePalette
IMPORT CalcDevs,ScatterDevices,SetDev,UnreserveDevices,UpdateDevices
ParamSize equ 4 ; total bytes of params
dstWindow equ ParamSize+8-4 ; source Palette handle
; The ActivatePalette stack frame is defined at the global level so it can be accessed
; by each of the routines subsidiary to ActivatePalette and thereby avoid gross parameter
; passing. All such subsidiary routines will link with A4 and not A6 thus keeping
; ActivatePalette's stack frame intact. D3 is used to hold any error condition.
; It is moved to D0 before we quit.
UpdatePalette
LINK A6,#spVarSize
MOVEM.L D3-D4/A2-A4,-(SP)
MOVEQ #1,D3
CLR.L WindowCopy(A6) ; No top window
MOVE.L PMgrHandle,A2
MOVE.L dstWindow(A6),A3 ; In this case, really, a PaletteHandle
BRA.S FoundPltt ; Jump into middle of ActivatePalette
ActivatePalette
Link A6,#spVarSize ; build stack frame
MoveM.L D3-D4/A2-A4,-(SP) ; save registers
MoveQ #1,D3 ; set error flag in case we branch
Move.L PMgrHandle,A2 ; get global handle
CmpA.L #PMgrNil,A2 ; is it nil?
Beq GoHome ; it has to be initialized
Move.L (A2),A0 ; dereference PMgrHandle AWC.PB500
Move nDevs(A0),D0 ; are there any clut devices? AWC.PB500
Beq GoHome ; no => punt AWC.PB500
Move.L dstWindow(A6),A3 ; get the window pointer
CmpA.L #Nil,A3 ; is it real?
Beq GoHome ; no => go home <AWC/PB150>
Move.L A3,WindowCopy(A6) ; save a copy for those who need it
Tst PortBits+RowBytes(A3) ; is it a new port?
Bpl.S TrySystem ; no => try for a system palette
Move.L GrafVars(A3),A0 ; get the GrafVars handle
Move.L (A0),A0 ; dereference it
Move.L PmFgColor(A0),A3 ; save the palette handle in GrafVars
CmpA.L #Nil,A3 ; is it nil?
Bne.S FoundPltt ; no => we've found it
TrySystem Move.L AppPalette,A3 ; get the layer's palette, if any AWC.PB457
Move.L A3,D0 ; CmpA.L #Nil,A0; is AppPalette nil? AWC.PB457
Bne.S FoundPltt ; no => use AppPalette AWC.PB457
Move.L (A2),A0 ; dereference PMgrHandle
Move.L SysPalette(A0),A3 ; get the system palette, if any
Move.L A3,D0 ; CmpA.L #Nil,A3; is SysPalette nil? AWC.PB457
Beq GoHome ; yes => we can't do it
; past this point we will have locked PMgrHandle and PaletteH. We also save theGDevice
; and clear the InfoHandle variable.
FoundPltt Move.L A2,A0 ; copy PMgrHandle
_HLock ; lock it down
Move.L A3,A0 ; copy PaletteH
MOVE.L A3,PaletteH(A6) ; and save a handle, too
_HLock ; lock it down as well
Move.L (A2),A4 ; dereference PMgrHandle
Move.L A4,PMgrPtr(A6) ; save a copy of the pointer
Move.L PListHandle(A4),A0 ; get PListHandle
_HLock ; lock it down
Move.L (A0),PListPtr(A6) ; save pointer to palette list
Move nDevs(A4),Devices(A6) ; save number of devices in our list
Lea DevHandles(A4),A0 ; point A4 at first device handle
Move.L A0,PDevPtr(A6) ; save pointer to start of device list
Move.L theGDevice,SaveGDev(A6) ; save theGDevice handle
Clr.L InfoHandle(A6) ; mark it as unallocated
Move.L (A3),A4 ; dereference PaletteH
Move.L A4,PalettePtr(A6) ; save it for posterior
Move pmEntries(A4),D4 ; fetch number of entries
Move D4,myEntries(A6) ; save it for posterity
Clr MAnimators(A6) ; MAnimators := 0
Clr MTolerators(A6) ; MTolerators := 0
; Check to see on which devices the window is now rendered
Jsr CalcDevs ; determine the new and frontmost device sets
CLR -(SP) ; No SetEntries
JSR ScatterDevices ; Scatter anyone who needs it <dvb3>
Tst.L FrontSet(A6) ; is this window frontmost on any device?
Beq NoFunStuff ; no => skip our wonderful rendering code
; Count the number of animating and tolerant colors. Mark explicit, dithered, and
; courteous colors as "handled" so we won't bother with them in SetDev et al.
Lea pmInfo(A4),A4 ; point us at the first ColorInfo
MOVE myEntries(A6),D4 ; set up loopy variable
Bra.S ExamEnd ; jump into DBra loop
ExamLoop Move ciUsage(A4),D1 ; copy ciUsage field of current entry
BTst #AnimatedBit,D1 ; pmAnimated?
Beq.S CheckTolrnt ; no => check for other kinds of usage
AddQ #1,MAnimators(A6) ; bump number of animating colors
Bra.S NextColor ; continue
; If a tolerant color is all black or white and not explicit, it's already in the palette, so
; we don't need to add it. We do this by only checking for black or white entries when the entry
; is not explicit. The code later will catch entries that are trying to set the first or last
; colors in the device color table.
CheckTolrnt BTST #TolerantBit,D1
BEQ.S HandleColor
if 0 then
; <SAH 28OCT93>
; I believe this code to be right, however it causes black to be stuck in the palette in many
; cases where it never used to. The net result is that synthetic font caches are built with
; black being odd indices (not ff) and never being flushed once the palette is thrown away.
; We need to figure out how to flush the font caches for real for all processes and then we
; can bring this code back in.
BTST #ExplicitBit,D1 ; is it explicit? <sah 9SEP93>
BNE.S AlwaysAdd ; yes, so we must add it <sah 9SEP93>
endif
MOVE.L ciRGB+red(A4),D0 ; D0: Rhi.Rlo.Ghi.Glo <dvb10>
MOVE.B ciRGB+blue(A4),D0 ; D0: Rhi.Rlo.Ghi.Bhi <dvb10>
TST.L D0 ; Is it all zero's? <dvb10>
BEQ.S HandleColor ; Yes => it's Black, its handled. <dvb10>
ADDQ.L #1,D0 ; =FFFFFF? It's White, its handled <dvb10>
BEQ.S HandleColor ; <dvb10>
AlwaysAdd AddQ #1,MTolerators(A6) ; yes => bump number of tolerant colors
Bra.S NextColor ; continue
HandleColor BSet #HandledBit,ciUsage(A4) ; mark explicit and normal colors as handled
NextColor Add #ciSize,A4 ; bump address to next ColorInfo
ExamEnd DBra D4,ExamLoop ; loop for all pmEntries
; See if we have any animating or tolerant entries. If not, we can skip most of this
Move MAnimators(A6),D0 ; do we have any animating AWC PB223
Or MTolerators(A6),D0 ; or tolerant entries? AWC PB223
Beq NoFunStuff ; no => just clean up the world AWC.PB508
; Allocate a scratch buffer
Move.L #InfoHandSz,D0 ; size of our scratch area AWC
_NewHandle ,CLEAR ; allocate a scratch area
Bne UnlockEm ; we couldn't get it - D3 still says "error" AWC.PB508
Move.L A0,InfoHandle(A6) ; save it
_HLock ; lock it
Move.L (A0),A0 ; dereference it
Move.L A0,InfoPtr(A6) ; save dereferenced ptr
; Call SetDev to render or record the Palette on each device, as appropriate.
MoveQ #0,D4 ; clear device counter
DeviceLoop Move.L FrontSet(A6),D0 ; grab the front device set AWC PB223
BTst D4,D0 ; frontmost on this clut device? AWC PB223
Beq.S NoDevError ; no => jump across SetDev AWC PB223
Move MAnimators(A6),Animators(A6) ; copy MAnimators
Move MTolerators(A6),Tolerators(A6) ; copy MTolerators
Move D4,CurDevice(A6) ; copy it for SetDev
Jsr SetDev ; render palette; did we get an error?
Beq.S NoDevError ; did we find an error?
AddQ #1,D3 ; bump our error count
NoDevError AddQ #1,D4 ; we've examined another device
Cmp Devices(A6),D4 ; have we done them all
Bmi.S DeviceLoop ; no => do another
Move.L SaveGDev(A6),theGDevice ; restore theGDevice handle AWC.PB508
NoFunStuff Move.L PMgrPtr(A6),A0 ; get the PMgrHandle pointer AWC PB223
Move.L PListHandle(A0),A0 ; get the PListHandle
Move.L (A0),A0 ; dereference it
Move.L PalettePtr(A6),A1 ; get the Palette
Move pmPrivate(A1),D0 ; get the entry number
And #PIdMask,D0 ; clear the flag bits
Move Reserves(A0,D0.W*8),D0 ; does this palette have anything reserved?
Beq.S NoneRsrvd ; no => forget about clearing AWC PB223
; Clear any unused devices and update device bitmap
Move.L PMgrPtr(A6),A0 ; get the PMgrHandle pointer AWC PB223
Move.L pmDevices(A1),D0 ; get former device set
Move.L DeviceSet(A6),D1 ; get new device set
Not.L D1 ; complement the current set
And.L D1,D0 ; remove any current bits
Beq.S NoneRsrvd ; if none needing unreserving, quit
JSR UnreserveDevices ; Pass: A0->Pmgr data, A1->palette, D0 = devmask
NoneRsrvd CLR -(SP) ; No Setentries
JSR ScatterDevices ; Scatter those devices that unreserving affected
JSR UpdateDevices
Move.L DeviceSet(A6),pmDevices(A1) ; copy the new device set
SubQ #1,D3 ; if now 0 then we got through with no errors
UnlockEm Move.L PMgrPtr(A6),A0 ; get the master pointer
Move.L PListHandle(A0),A0 ; get this handle
_HUnlock ; unlock it
Move.L A2,A0 ; copy PMgrHandle
_HUnLock
; clear the dirty bit and restore the user's ciUsage fields
Move.L PalettePtr(A6),A0 ; get Palette pointer
BClr #DirtyBit,pmPrivate(A0) ; clear the dirty bit
Move pmEntries(A0),D0 ; fetch number of entries
Lea pmInfo(A0),A0 ; point us at the first ColorInfo
Bra.S UnsetEnd ; jump into DBra loop
UnsetLoop Move ciUsage(A0),D1 ; copy ciUsage field of current entry
And #ClearBits,D1 ; clear all but the user's flags
Move D1,ciUsage(A0) ; restore it
AddA.L #ciSize,A0 ; bump A4 to the next color info
UnsetEnd DBra D0,UnsetLoop ; loop for all pmEntries ColorInfo's
Move.L A3,A0 ; copy PaletteHandle to A0
_HUnlock ; unlock it
Move.L InfoHandle(A6),A0 ; get scratch handle
CmpA.L #Nil,A0 ; was it allocated
Beq.S NoError ; no => don't dispose it
_DisposHandle ; get rid of it
NoError MoveQ #0,D3 ; clear error flag
GoHome Move.L D3,D0 ; copy error flag
MoveM.L (SP)+,D3-D4/A2-A4 ; restore registers
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE Allocate; LOCAL;
;
PMAllocate PROC EXPORT
IMPORT ClaimIndex,FindLink,Pillage,GimmeIndex
; We have one or more animating entries. For each entry in myPalette, look to see if it is
; animating. If so, look to see if it exists on this device. If not, look to see if we can
; allocate it on this device.
MoveM.L D3/D4/A2-A3,-(SP) ; save registers
TST Animators(A6) ; Have anything to animate?
BEQ GoHome
Move.L PalettePtr(A6),A3 ; get palette pointer
MoveQ #0,D4 ; D4 is the entry number
CLR.L D2 ; Clear upper bits of D2, for BF ops
CLR.L D3 ; Clear upper bits of D3, for BF ops
LEA pmInfo(A3),A2 ; bump A2 to the first ColorInfo
Bra.S AnimateEnd ; jump into loop
AnimateLoop Move ciFlags(A2),D0 ; examine "handled"
Bmi.S NextAnimate ; it was explicit or courteous; ignore it
BTst #AnimatedBit,D0 ; are we animating?
Beq.S NextAnimate ; no => ignore it
BTST #ExplicitBit,ciFlags+1(A2) ; is it animated+explicit? <dvb4>
BEQ.S notExplicit ; no, just normal animated... doit. <dvb4>
MOVE D4,D3 ; Move it here, for setting within clutrange
AND BlackIndex(A6),D3 ; Roll over into range
BEQ.S NextAnimate ; Got zero = "white"? So sorry, sir. <dvb4>
CMP BlackIndex(A6),D3 ; are we trying to get "black"? <dvb4>
BEQ.S NextAnimate ; No way, Mr. <dvb4>
BFTST availBits(A6){D3:1} ; This index already explicitly animated?
BNE.S NextAnimate ; Yes! Don't take it a second time.
BFSET availBits(A6){D3:1} ; Mark this explicit entry as used.
Clr -(SP) ; clear index result
Move ciPrivate(A2),-(SP) ; push animation link info (first word only)
Jsr FindLink ; FindLink(Device,myPalette^^.pmInfo[i].ciPrivate)
Move (SP)+,D2 ; pop the index result
Bne.S HadIndex ; true => it's still there - mark it as "handled"
MOVE D3,-(SP) ; we want this index <dvb4>
Jsr Pillage ; steal this index <dvb4>
MOVE D3,D2 ; D2 = index we want (the same for explicit)<dvb4>
BRA.S GotIndex ; And finish with this entry
notExplicit Clr -(SP) ; clear index result
Move ciPrivate(A2),-(SP) ; push animation link info (first word only)
Jsr FindLink ; FindLink(Device,myPalette^^.pmInfo[i].ciPrivate)
Move (SP)+,D2 ; pop the index result
Bne.S HadIndex ; true => it's still there - mark it as "handled"
SUBQ #2,SP ; Space for result
BSR GimmeIndex ; Get the next available index
MOVE (SP)+,D2 ; Did we get a color? Put index in D2
BEQ.S NextAnimate ; No=>but keep looping, for Explicits.
GotIndex MOVE D2,-(SP) ; Push index we want
JSR Pillage ; Knock off anyone else on it.
MOVE D4,D0 ; Set D0 = entry we're stealing for
MOVE.L A2,A0 ; setup for claim
BSR ClaimIndex
HadIndex BSet #HandledBit,ciFlags(A2) ; set "handled" bit
NextAnimate AddA.L #ciSize,A2 ; bump us to the next ColorInfo
AddQ #1,D4 ; bump entry number
AnimateEnd CMP pmEntries(A3),D4 ; At end of entries yet?
BLT AnimateLoop ; loop for all pmEntries
GoHome MoveM.L (SP)+,D3/D4/A2-A3 ; restore registers
Rts ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE CheckAllDeviceCluts;
;
; Set scatterbits for all indices in all devices which
; don't match the correct default clut.
CheckAllDeviceCluts PROC EXPORT
IMPORT CheckDeviceColors
MOVEM.L A0-A3/D3-D4,-(SP) ; save 'em.
MOVE.L PMgrHandle,A2
MOVE.L A2,A0 ; PMgrHandle <dvb5>
_HLock ; Lock it down <dvb5>
MOVE.L (A2),A3 ; Redereference <dvb5>
MOVE nDevs(A3),D3 ; number of devices, for looping <dvb5>
SUBQ #1,D3 ; less one for DBRAing <dvb5>
CLR.L D4 ; D4 = device update mask <dvb5>
gLoop SUB #2,SP ; space for boolean result
MOVE.L DevHandles+DevHandle(A3,D3*8),-(SP) ; push gDevice handle <dvb5>
JSR CheckDeviceColors ; check the device
TST (SP)+ ; Was the device up to date?
BEQ.S gLoopEnd ; Yes=>try next device
BSET D3,D4 ; No=>mark update bit
gLoopEnd DBRA D3,gLoop ; loop for all devices <dvb5>
OR.L D4,scatterDevs(A3) ; mark devices for scattering <dvb5>
MOVE.L A2,A0 ; PMgrHandle
_HUnlock
MOVEM.L (SP)+,A0-A3/D3-D4 ; save 'em.
RTS
;---------------------------------------------------
;
; FUNCTION CheckForProcessMgr:Boolean;
;
; Determine if the process mgr is present using Gestalt.
; (we assume that gestaltLaunchControl iff processMgr is here)
; Affect only A0/D0, since Gestalt is an OS trap.
; return Z-flag Clear if the process mgr is here (BNE ProcMgrTrue)
CheckForProcessMgr PROC EXPORT
MOVE.L ExpandMem,A0
TST $128(A0)
RTS
;---------------------------------------------------
;
; PROCEDURE PMgrExit; AAA2/12;
;
; Someone should call here when an application quits. Please.
;
PMgrExit PROC EXPORT
IMPORT ScatterDevices,UpdateDevices,DisposeAppPalettes
IMPORT CheckForJuggler,CheckForProcessMgr
PXVars RECORD {A6Link},DECREMENT
result DS.B 0 ;Result: nothing
return DS.B 4
A6Link DS.B 4 ; old contents of A6
frontPSN DS.B 8 ; a 64-bit process serial number
myPSN DS.B 8 ; likewise
inFront DS.B 2 ; a boolean
IF (forRom OR theFuture) THEN
wList DS.B 4 ; saved window list
ENDIF
linkSize DS.B 0 ; linky number
ENDR
WITH PXVars
LINK A6,#linkSize
movem.l a0-a2/d0-d2,-(sp) ; Those pesky c routines <mc8>
sub.l a0,a0 ; Pass the current process (0)
moveq #12,d0 ; _TrashProcess
;_FigmentDispatch ; let everyone know this stuff is gone
dc.w $A0A4
movem.l (sp)+,a0-a2/d0-d2 ; Restore em
IF (forRom OR theFuture) THEN
MOVE.l WindowList,wList(A6) ; <SM2> FM save the current window list
ENDIF
TST.B QDExist ; if InitGraf has not been called yetÉ
BNE.S @doNothing ; (a5) not valid and there is nothing to do
CMP.L #PMgrNil,PMgrHandle ; If the palette manager doesnt exist...
BEQ.S @doNothing
CLR.L AppPalette
JSR DisposeAppPalettes
MOVE.L (A5),A0
BTST #3,QDSpare0(A0) ; Any change to color env?
BEQ.S @doNothing
BSR.S CheckForProcessMgr
BEQ.S @front ; if no process mgr, assume we're in front
MOVE #$0100,inFront(A6) ; default inFront to true
SUBQ #2,SP ; space for result
PEA frontPSN(A6)
_GetFrontProcess
TST (SP)+ ; problem getting front psn?
BNE.S @front ; YES => just zap the cluts
CLR.L myPSN(A6)
MOVE.L #kCurrentProcess,myPSN+4(A6)
SUBQ #2,SP ; space for OSErr result
PEA frontPSN(A6)
PEA myPSN(A6)
PEA inFront(A6)
_SameProcess ; are we the front process?
ADDQ #2,SP ; OSErr leaves inFront true from above
TST.B inFront(A6)
BEQ.S @doNothing
@front
JSR CheckAllDeviceCluts ; A pretty simple patch, really.
CLR -(SP) ; No Setentries on Scatter
JSR ScatterDevices
BSR CheckForJuggler ; Is Jugglertm active?
BNE.S @doNothing ; No=>WMgr is void, next line dangerous
JSR UpdateDevices
MOVE.L mainDevice,theGDevice
@doNothing
IF (forRom OR theFuture) THEN
MOVE.l wList(A6),WindowList ; <SM2> FM restore the current window list
ENDIF
UNLK A6
RTS
;---------------------------------------------------
;
; FUNCTION CheckForJuggler:Boolean;
;
; Set D0 to FFFFFFFF if Juggler is absent, and 00000000 if present. Affect
; No other registers.
CheckForJuggler PROC EXPORT
MOVE.L A0,-(SP) ; stow it.
Move #JugglerTrap,D0 ; #$A88F AWC PB224
_GetTrapAddress ; find out what the trap is
Move.L A0,-(SP) ; save it
Move #UnimplementedTrap,D0 ; #$A89F
_GetTrapAddress ; where do unimplemented traps go
CmpA.L (SP)+,A0 ; are we Jugglerªing?4
SEQ D0 ; D0 = 00 is juggling, FF if not
EXTB.L D0 ; Make it fully big.
MOVEA.L (SP)+,A0 ; It don't hit the CCR.
RTS
;---------------------------------------------------
;
; PROCEDURE RecordPalette(myPalette: PaletteHandle); LOCAL;
;
; Copies myPalette into the PListHandle and records (in the pmPrivate field) where
; it lies in that list. If there are no free spaces in the PListHandle then that
; handle is resized. If it can't be resized, RecordPalette returns an error in D0.
; Otherwise a new handle is allocated for myPalette's pmSeeds field. If one can't
; be allocated, RecordPalette returns an error. It will also return an error if the
; PMgrHandle is nil. If RecordPalette returns an error, it first disposes of
; myPalette so the caller doesn't have to worry about watching the error code.
RecordPalette PROC EXPORT
ParamSize equ 4 ; total bytes of params
myPalette equ ParamSize+8-4 ; source Palette handle
VarSize equ 0
Link A6,#VarSize ; build stack frame
MoveM.L D3/A2-A4,-(SP) ; save registers
Move.L myPalette(A6),A4 ; get my palette first in case we branch to Error
Move.L PMgrHandle,A2 ; get the PMgrHandle
CmpA.L #PMgrNil,A2 ; has it been initialized?
Beq Error ; no => handle the error (.S won't reach)
Move.L (A2),A0 ; dereference the PMgrHandle
Move.L PListHandle(A0),A3 ; get the handle to the list of palettes
MoveQ #0,D0 ; clear high word
Move SeedHSize(A0),D0 ; get length of seeds handles
_NewHandle ,CLEAR ; allocate it; did we succeed?
Bne Error ; no => handle the error (.S won't reach)
Move.L (A4),A1 ; dereference myPalette
Move.L A0,pmSeeds(A1) ; store the seeds handle in it
Move.L (A2),A1 ; redereference the PMgrHandle
Move FreeSpaces(A1),D0 ; get number of free slots; are any left?
Bne.S FindOne ; yes => don't resize it; search for a free one
MoveQ #0,D3 ; clear high word
Move APalettes(A1),D3 ; get current size
Move.L D3,D0 ; copy it
Add #ListSpace,D0 ; bump it to add more room
Bmi.S Error ; return an error if it wraps
Lsl.L #3,D0 ; multiply by 8
Move.L A3,A0 ; copy PListHandle to A0
_SetHandleSize ; resize it
Bne.S Error ; we couldn't do it
; Now we have to clear all of the new entries we just created.
Move.L A3,A0 ; get PListHandle
Move.L (A0),A0 ; redereference this
Lea (A0,D3.W*8),A0 ; point us at the block to clear
Move.L #ListSpace,D0 ; get how many entries to clear
Bra.S ClearEnd ; jump into loop
ClearLoop Clr.L (A0)+ ; clear the Palette field
Clr.L (A0)+ ; clear the animation field
ClearEnd DBra D0,ClearLoop ; loop for ListSpace entries
AddQ #1,D3 ; D3 is palette's position in PListHandle
Move.L (A3),A0 ; dereference PListHandle
Lea (A0,D3.W*8),A0 ; point A0 at the current position
Move.L (A2),A1 ; redereference the PMgrHandle
Move #ListSpace-1,FreeSpaces(A1) ; number of spaces we've added AWC.PB378
Bra.S Cleanup ; share common code
; We have a free one somewhere in the list. Search forwards until we find one we can use.
; A1 is still pointing at the dereferenced PMgrHandle.
FindOne Move APalettes(A1),D0 ; get number of active handles
Add FreeSpaces(A1),D0 ; calculate total number of entries
MoveQ #0,D3 ; initialize our counter
Move.L (A3),A0 ; dereference PListHandle
Bra.S FindEnd ; jump into loop
FindLoop Move.L PaletteRef(A0),D1 ; get first entry
Beq.S FoundIt ; we've got one
AddQ #PLstEntrySz,A0 ; bump to the next entry
AddQ #1,D3 ; bump our counter
FindEnd DBra D0,FindLoop ; repeat for all spaces
Bra.S Error ; this should not happen
; when we reach this section of common code, A1 = PMgrHandle^, D3 is the position of
; the palette, and A0 points to PListHandle^^[D3]
FoundIt SubQ #1,FreeSpaces(A1) ; decrement the number free
Cleanup AddQ #1,APalettes(A1) ; bump the number used
Move.L A4,PaletteRef(A0) ; record the palette handle in PListHandle
Clr.L Reserves(A0) ; clear the number of entries it reserves
Move.L (A4),A0 ; dereference the Palette
Move pmPrivate(A0),D0 ; grab the current update values AWC.PB457
And #UpdateMask,D0 ; clear away all but the update bits AWC.PB457
Or D0,D3 ; OR palette number with the update bits AWC.PB457
Move D3,pmPrivate(A0) ; this is the number of the palette
MoveQ #0,D0 ; no error
Bra.S GoHome ; we're done-oh!
Error Move.L A4,A0 ; get Palette handle
_DisposHandle ; get rid of it
MoveQ #1,D0 ; set an error
GoHome Tst.L D0 ; set condition codes for return
MoveM.L (SP)+,D3/A2-A4 ; restore registers
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; FUNCTION NewPalette(entries: INTEGER; srcColors: CTabHandle; srcUsage,srcTolerance:
; INTEGER) : PaletteHandle; INLINE $AA91;
;
; Allocate a new palette and fill it with information from myColors. Set the usage
; field of each ciInfo to myUsage and set the tolerance to myTolerance. If myColors
; is nil we initialize all the colors to black.
NewPalette FUNC EXPORT
ParamSize equ 10 ; total bytes of params
Palette equ ParamSize+12-4 ; function result
entries equ Palette-2 ; number of entries in Palette
srcColors equ entries-4 ; Color table handle
srcUsage equ srcColors-2 ; default usage for each color in Palette
srcTolerance equ srcUsage-2 ; default tolerance for each color in Palette
VarSize equ 0
Link A6,#VarSize ; build stack frame
MoveM.L D3/A2,-(SP) ; save registers
Clr.L Palette(A6) ; set the result to nil
Move entries(A6),D3 ; fetch number of entries
MoveQ #0,D0 ; clear it out
Move D3,D0 ; copy it for a calculation
AddQ #1,D0 ; add one for the header
Lsl.L #4,D0 ; multiply by 16
_NewHandle ,CLEAR ; get the handle; did we get an error?
Bne.S GoHome ; yes => we're done for
Move.L A0,A2 ; no => save the handle
Move.L A2,-(SP) ; push handle
Jsr RecordPalette ; allocates a seed's handle and records palette
Bne.S GoHome ; it disposed the palette handle if it failed
; A2 contains the handle to the new Palette. Return the handle, then start by dereferencing it.
; For now we'll just clear everything. Note that we're making use of the fact that
; the size of the header is the same as an entry itself, so we can fall straight
; into the DBra and expect it to clear Entries+1 records! Also, zero the window field
; so we know that this palette is floating
Move.L A2,Palette(A6) ; return the result
Move.L (A2),A0 ; dereference Palette handle
Move D3,pmEntries(A0) ; copy pmEntries
Clr.L pmWindow(A0) ; zero the window field
Move D3,D0 ; get entries into D0
Move srcUsage(A6),D1 ; copy usage to D1
Swap D1 ; put usage into high word
Move srcTolerance(A6),D1 ; put tolerance into low word
Lea pmInfo+ciUsage(A0),A0 ; point A0 at first ColorInfo
Bra.S EntryEnd ; jump into the loop
EntryLoop Move.L D1,(A0) ; set ciUsage (high word) and ciTolerance (low word)
AddA #ciSize,A0 ; bump A0 to the next ciUsage field
EntryEnd Dbra D0,EntryLoop ; loop for all entries
Move.L srcColors(A6),A1 ; get ctabhandle
CmpA.L #Nil,A1 ; is it nil?
Beq.S NoCTab ; yes => skip the copy
Move.L (A1),A1 ; dereference the source color table
Move ctSize(A1),D0 ; get last color table entry
AddQ #1,D0 ; make it number of entries; is it >= 1?
Ble.S NoCTab ; no => we're done
Move.L (A2),A0 ; redereference PaletteHandle
AddA.L #pmInfo+ciRGB+red,A0 ; bump A0 to pmInfo.ciRGB.red
AddA.L #ctTable+rgb+red,A1 ; bump A1 to ctTable.red
; put min(ctSize+1,pmEntries) into D0
Cmp D0,D3 ; compare color table size to palette size
Bge.S UseAsIs ; if D0 is less than D3, we'll use it as is
Move D3,D0 ; copy the lower value into D0
UseAsIs MoveQ #0,D1 ; D1 points at this entry
Bra.S CopyEnd ; jump into loop
CopyLoop Move.L red(A1),red(A0) ; copy red and green
MOVE.B red(A1),red+1(A0) ; and into lo byte of red, <dvb11>
MOVE.B green(A1),green+1(A0) ; and into lo byte of green, <dvb11>
Move blue(A1),blue(A0) ; copy blue
MOVE.B blue(A1),blue+1(A0) ; and into lo byte of blue. <dvb11>
AddQ.L #ColorSpecSize,A1 ; bump A1 to next ColorSpec
AddA.L #ciSize,A0 ; bump A0 to next ColorInfo
CopyEnd Dbra D0,CopyLoop ; loop until the copy is complete
NoCTab MoveQ #0,D0 ; no error
GoHome MoveM.L (SP)+,D3/A2 ; restore registers
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; FUNCTION GetNewPalette(paletteID: INTEGER) : PaletteHandle; INLINE $AA92;
;
; GetNewPalette gets a resource of type 'pltt' with the specified ID and clears
; all the private fields. It then returns the data structure as a PaletteHandle.
;
GetNewPalette FUNC EXPORT
ParamSize equ 2 ; total bytes of params
Palette equ ParamSize+12-4 ; function result
paletteID equ Palette-2 ; number of entries in Palette
VarSize equ 0
Link A6,#VarSize ; build stack frame
Move.L A2,-(SP) ; save registers
Clr.L Palette(A6) ; set result to Nil
; Load the data and detach it from resource manager
Clr.L -(SP) ; make space for result
Move.L #'pltt',-(SP) ; push resource type
Move paletteID(A6),-(SP) ; push resource ID
_GetResource ; get the resource
Move.L (SP)+,D1 ; get handle off the stack
Beq.S GoHome ; if nil we go home
Move.L D1,A2 ; copy it to A2
Move.L D1,-(SP) ; push it back on the stack
_DetachResource ; disconnect from resource manager
Move.L A2,A0 ; copy it for the HNoPurge AWC.PB480
_HNoPurge ; we can't handle purged palettes AWC.PB480
Tst D0 ; did it return an error? AWC.PB480
Bne.S GoHome ; yes => go home AWC.PB480
Move.L (A2),A0 ; dereference palette AWC.PB457
Move #AllUpdates,D1 ; set D1 to the default AWC.PB457
Move plttUpdates(A0),D0 ; get update bits AWC.PB457
Bpl.S NoResUpdate ; the user didn't specify any AWC.PB457
ADD D0,D0 ; put the bits in the correct place AWC.PB457
Move D0,D1 ; put the result into D1 AWC.PB457
NoResUpdate Move D1,pmPrivate(A0) ; put them in the correct place AWC.PB457
Move.L A2,-(SP) ; push the handle
Jsr RecordPalette ; allocates a seeds handle and records palette
Bne.S GoHome ; it disposed the palette handle if it failed
Move.L A2,Palette(A6) ; save Palette in result space
; clear the window field and also the private fields
Move.L (A2),A2 ; dereference it
; Clr.L pmWindow(A2) ; set window field; this palette floats
Clr.L pmDevices(A2) ; clear device bitmap
GoHome Move.L (SP)+,A2 ; restore registers
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE ClaimIndex; LOCAL;
;
; Assume that index D2 on CurDevice(A6) is unowned (it was free or has been pillaged).
; Now, we will claim it for palette entry D0 of PalettePtr(A6). We will link it thru
; the Linktabs, mark the Reserve bit in the color table, and zap the seed so that
; no tolerant entries later take it.
;
; In: D0 = Palette entry number
; D2 = device index number
; A0 -> colorinfo field within palette
ClaimIndex PROC EXPORT
MOVE.L DevCTab(A6),A1
MOVE.L (A1),A1 ; A1 -> color table
SUBQ #4,SP
_GetCTSeed ; (changes no registers)
MOVE.L (SP)+,ctSeed(A1) ; alter the seed (we've changed something, eh?)
BSet #HandledBit,ciFlags(A0) ; mark this entry as handled
Move.L ciRGB+red(A0),ctTable+RGB+red(A1,D2.W*8) ; update red and green
Move ciRGB+blue(A0),ctTable+RGB+blue(A1,D2.W*8) ; update blue
AddQ #1,Updates(A6) ; we've changed something
BSet #ctReserveBit,ctTable+value(A1,D2.W*8) ; reserve it
Move.L DevLinks(A6),A1 ; point A1 at LinkTab
And #$7FFF,D0 ; ensure that the top bit is off
Or #$6000,D0 ; set the top bits to 011
Move D0,BackLink(A1,D2.W*4) ; set backward link to entry | $6000
; Calculate a link to this new guy in D0. This will go in ciPrivate and, if we already
; had a link, into the BackLink of the old guy.
Move CurDevice(A6),D0 ; get current device again
Lsl #8,D0 ; shift device into upper byte
Or D2,D0 ; OR in the device number
BSet #15,D0 ; set the three highest bits to 100
; Copy the old link then set the new one. Then look to see if the old link was real.
; If so, we have some work to do. If not, initialize the link by setting the forelink
; to the palette number. The back link has already been set to the entry number.
Move ciPrivate(A0),D1 ; copy the old link
Move D0,ciPrivate(A0) ; point ciPrivate at the new guy
Tst D1 ; did we have any old links?
Bne.S OldLinks ; yes => relink it
Move.L PalettePtr(A6),A0 ; get pointer to palette
Move pmPrivate(A0),D0 ; grab number of this palette
And #PIdMask,D0 ; clear the flag bits
Or #$6000,D0 ; to make it non-zero, set the top bits to 011
Move D0,ForeLink(A1,D2.W*4) ; set forward link to palette | $6000
Bra.S FixRefCount ; fix up the palette
OldLinks Move D1,ForeLink(A1,D2.W*4) ; point Dev[FoundIndex] at old ciPrivate
BfExtU D1{24:8},D2 ; grab index number (0..255)
BfExtU D1{19:5},D1 ; grab device number (0..31)
Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Move.L PMgrPtr(A6),A1 ; get base pointer
AddA.L #LinkTabs,A1 ; bump it to the LinkTabs
Move D0,BackLink(A1,D1.L*4) ; set the backward link
FixRefCount Move.L PListPtr(A6),A0 ; get PListPtr
Move.L PalettePtr(A6),A1 ; get palette
Move pmPrivate(A1),D0 ; get palette number
And #PIdMask,D0 ; clear the flag bits
AddQ #1,Reserves(A0,D0.W*8) ; bump number of reserves
ADDQ #1,updates(A6) ; we've made a change
RTS
;---------------------------------------------------
;
; PROCEDURE ClearPalette(cPalette: PaletteHandle); LOCAL;
;
; Release all animated entries owned by cPalette.
;
ClearPalette PROC EXPORT
IMPORT ClearStrand
ParamSize equ 4 ; total bytes of params
cPalette equ ParamSize+8-4 ; source Palette handle
VarSize equ 0
Link A6,#VarSize ; build stack frame
MoveM.L D2-D4/A2-A4,-(SP) ; save registers
Move.L PMgrHandle,A3 ; get palette manager handle
CmpA.L #PMgrNil,A3 ; are we initialized?
Beq.S GoHome ; no => quit AWC.PB377
Move.L (A3),A3 ; dereference it
Move.L cPalette(A6),A1 ; get palette handle AWC.PB457
Move.L (A1),A2 ; dereference it AWC.PB457
; Examine and remember the number of reserves this palette still has. Clear the number.
Move pmPrivate(A2),D0 ; get the number of this palette
And #PIdMask,D0 ; clear away update bits
Move.L PListHandle(A3),A0 ; get the palette list handle
Move.L (A0),A0 ; dereference it
CmpA.L PaletteRef(A0,D0.W*8),A1 ; is this the correct handle? AWC.PB462
Bne.S BadPalette ; no => don't dispose anything AWC.PB462
Move Reserves(A0,D0.W*8),D3 ; remember how many animating entries it has
Clr.L Reserves(A0,D0.W*8) ; clear the count
; Now clear each of the seeds this palette knows about, so that we'll update if we
; become active again.
Clr.L pmDevices(A2) ; clear devices field
Move.L pmSeeds(A2),A0 ; get seeds handle
Move.L (A0),A0 ; dereference it
Move SeedHSize(A3),D0 ; get size of handle
Lsr #2,D0 ; divide by 4
Bra.S SeedEnd ; start clear loop
SeedLoop Clr.L (A0)+ ; clear the remembered seed
SeedEnd DBra D0,SeedLoop ; do it again
; Now check to see if we have any animating entries which we can dispose
Tst D3 ; were there any animating entries?
Beq.S GoHome ; no => quit
; run through every color to make sure it is not reserving any entries on any device
; by examining what the PaletteManager has to say about this palette as well as what
; each entry's ciPrivate field has to say about the subject. Leave pmPrivate field
; (which tells PMgr which palette we ought to be) alone.
Move pmEntries(A2),D0 ; get number of entries
AddA.L #pmInfo,A2 ; bump A2 to the first ColorInfo
Lea DevHandles(A3),A4 ; point A4 at PMgrDevices
AddA.L #LinkTabs,A3 ; point A3 to LinkTabs
Bra.S EntryEnd ; jump into loop
EntryLoop Move ciPrivate(A2),D3 ; get the current link information
Bpl.S NextEntry ; if positive it's not a link
Jsr ClearStrand ; If it's a link, wipe out it and its successors. <dvb3>
OR.L D4,scatterDevs-LinkTabs(A3) ; A tricky offset; set bits to scatter devices <dvb3>
NextEntry Clr ciFlags(A2) ; shut down any crap
Clr ciPrivate(A2) ; clear it
AddA.L #ciSize,A2 ; bump A2 to the next ColorInfo
EntryEnd DBra D0,EntryLoop ; loop for all pmEntries
GoHome MoveQ #0,D0 ; clear error condition
BadPalette MoveM.L (SP)+,D2-D4/A2-A4 ; restore registers AWC.PB457
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE ClearStrand(Linkhead); LOCAL;
;
; Clear all device indexes which start on the given strand, taken from
; a ciPrivate field. Mark bit 4 of the value field of indices which must
; be returned to the environment.
; Enter with D3 = the linkhead, A3 = Linktab base, A4 = gDevice list base
; return with D4 = bitmask of those devices needing scattering
; We'll stomp on A0,D1,D2,D3,D4
; (this code was moved out of ClearPalette so others could call it <dvb3>)
ClearStrand PROC EXPORT
CLR.L D4 ; no devices need scattering yet.
LinkLoop BfExtU D3{19:5},D1 ; grab device number (0..31)
BfExtU D3{24:8},D2 ; grab index number (0..255)
Move.L DevHandle(A4,D1.W*8),A0 ; get the device handle
Move.L (A0),A0 ; dereference it
Move.L gdPMap(A0),A0 ; get handle to pixmap
Move.L (A0),A0 ; dereference pixmap
Move.L pmTable(A0),A0 ; get handle to CTab
Move.L (A0),A0 ; dereference CTab
Cmp ctSize(A0),D2 ; is index number <= entries - 1?
Bhi.S IgnoreIt ; no => don't unreserve it
MOVE #ctScatterVal,ctTable+value(A0,D2.W*8) ; unreserve it, mark scatterbit <dvb3>
BSET D1,D4 ; mark device for scattering <dvb3>
IgnoreIt Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Lea (A3,D1.L*4),A0 ; point A0 at next forward link
Move ForeLink(A0),D3 ; get next link
Clr.L ForeLink(A0) ; clear it for the next guy
LinkEnd Tst D3 ; is there another link to examine?
Bmi.S LinkLoop ; yes => go unlink it
GoHome Rts
;---------------------------------------------------
;
; PROCEDURE ErasePalette(ePalette: PaletteHandle); LOCAL;
;
ErasePalette PROC EXPORT
ParamSize equ 4 ; total bytes of params
ePalette equ ParamSize+8-4 ; PaletteHandle to dispose
VarSize equ 0
Link A6,#VarSize ; build stack frame
MoveM.L A2-A3,-(SP) ; save registers
Move.L ePalette(A6),A3 ; get the handle
Move.L (A3),A2 ; dereference it
Move.L pmSeeds(A2),A0 ; get the seeds handle while we have it
CmpA #Nil,A0 ; is it nil?
Beq.S DontDispose ; yes => punt
_DisposHandle ; it's gone
DontDispose Move.L WindowList,A0 ; get the window list for this layer AWC.PB506
Bra.S ListLoop ; continue AWC.PB439
CheckWindow Tst PortBits+Rowbytes(A0) ; by chance is it an old window? AWC.PB439
Bpl.S IgnoreWind ; yes => ignore it AWC.PB439
Move.L GrafVars(A0),A1 ; get GrafVars handle AWC.PB439
Move.L (A1),A1 ; dereference it AWC.PB439
Move.L PmFgColor(A1),D0 ; get the palette AWC.PB439
Cmp.L ePalette(A6),D0 ; is it correct? AWC.PB439
Bne.S IgnoreWind ; no => don't clear it AWC.PB439
Clr.L PmFgColor(A1) ; mark the window as Paletteless AWC.PB439
IgnoreWind Move.L nextWindow(A0),A0 ; grab the next window AWC.PB439
ListLoop Move.L A0,D0 ; CmpA.L #Nil,A0; another window? AWC.PB439
Bne.S CheckWindow ; yes => keep looking AWC.PB439
CmpA.L AppPalette,A3 ; are we disposing AppPalette? AWC.PB508
Bne.S NotAppPltt ; no => whew! AWC.PB508
Clr.L AppPalette ; okay, we won't try to find it anymore AWC.PB508
NotAppPltt Move pmPrivate(A2),D0 ; grab the last field we need from A2 AWC.PB439
And #PIdMask,D0 ; clear away flag bits
Move.L PMgrHandle,A2 ; get the main handle
CmpA.L #PMgrNil,A2 ; is it nil?
Beq.S GoHome ; yes => don't try to find it
Move.L (A2),A2 ; dereference it
Move APalettes(A2),D1 ; start with number of active palettes
Add FreeSpaces(A2),D1 ; add free spaces to get length of list
Cmp D1,D0 ; are we within the correct range?
Bpl.S GoHome ; no => punt
Move.L PListHandle(A2),A1 ; get handle to list of palettes
Move.L (A1),A1 ; dereference it
CmpA.L (A1,D0.W*8),A3 ; get this handle; do they match?
Bne.S GoHome ; no => in the future we may scan for it; for now, punt
Clr.L (A1,D0.W*8) ; it's no longer referenced
AddQ #1,FreeSpaces(A2) ; add 1 to free spaces
SubQ #1,APalettes(A2) ; subtract 1 from total palettes
GoHome MoveM.L (SP)+,A2-A3 ; restore registers
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE Correlate; LOCAL;
;
; Make sure we have sufficient colors for all Tolerant entries.
; We use the bit table (availbits) to make sure that we don't
; yank the same entry twice, or steal an animated explicit.
Correlate PROC EXPORT
IMPORT Pillage,DeltaRGB,GimmeIndex
MOVEM.L D3-D7/A2-A3,-(SP)
TST Tolerators(A6) ; Anything intolerant?
BEQ Leave ; No. Bail.
;
; First, we'll snag any explicit tolerant entries.
;
MOVEQ #0,D4 ; entry number we're examining
MOVE.L PalettePtr(A6),A2 ; A2->our palette
LEA pmInfo(A2),A2 ; A2->first colorInfo
MOVE.L DevCTab(A6),A3 ; A3 = device colortable handle
MOVE.L A3,A0 ; A0 gets handle
_HLock ; Lock it down
MOVE.L (A3),A3 ; A3-> device colortable
CLR.L D3 ; Clear the upper bits, for BF ops
ExplLoop MOVE ciUsage(A2),D7 ; D7 = usage of this entry
if 0 then
; <SAH 28OCT93>
; I'm taking this code out for now. It causes us to not add entries that we used to add. This code
; is not installed for IIci ROMs. It only began being installed for SuperMario. By taking it out we
; bring the palette manager back to the Quadra Rom but bring back a bug with tolerant+explicit+
; inhibited...
BMI.S ExplLoopEnd ; Already handled?
endif
BTST #TolerantBit,D7 ; A Tolerator?
BEQ.S ExplLoopEnd ; No, try next
BTST #ExplicitBit,D7 ; Explicit Tolerator?
BEQ.S ExplLoopEnd ; No, try next
MOVE D4,D3 ; D3 = palette entry
AND BlackIndex(A6),D3 ; D3 = explicit-ized clut index
BEQ.S ExplLoopEnd ; Don't take index zero! it's white, you know.
CMP BlackIndex(A6),D3 ; Are trying to snag black?
BEQ.S ExplLoopEnd ; No! No! No!
BFTST availBits(A6){D3:1} ; Already taken (by exp-anim, or earlier exp-tol)?
BNE.S ExplLoopEnd
BFSET availBits(A6){D3:1} ; No! Mark it as taken!
MOVE D3,-(SP) ; This is the index we want to steal
JSR Pillage ; Make sure noone else is settin on it
SUBQ #2,SP ; Space for colordelta result
PEA ciRGB(A2) ; Push palette's desired color
PEA ctTable+rgb(A3,D3*8) ; Push current device's color
bsr.l DeltaRGB ; How far apart are we?
MOVE (SP)+,D1
CMP ciTolerance(A2),D1 ; are we within tolerance?
BLS.S @GoodColor ; Yes=>don't change its RGB
LEA ctTable(A3,D3*8),A0 ; A0->colorspec we're doing
MOVE.L ciRGB+red(A2),rgb+red(A0) ; copy palette's red,green into device
MOVE ciRGB+blue(A2),rgb+blue(A0) ; copy palette's blue into device
BSET #ctTolBit,value(A0) ; Set the tolerator bit for index
SUB #4,SP ; space for result
_GetCTSeed ; put new seed
MOVE.L (SP)+,ctSeed(A3) ; into table
ADDQ #1,updates(A6) ; We've made a device change
@GoodColor BSET #HandledBit,ciFlags(A2) ; Mark entry as handled
ExplLoopEnd ADD #ciSize,A2 ; Bump A2 to next colorInfo in our palette
ADDQ #1,D4 ; D4 is next entry number
CMP myEntries(A6),D4 ; Up to, and not including, number of entries
BLT.S ExplLoop
ExplDone
;Now, we'll snag any regular tolerant entries.
MOVE.L PalettePtr(A6),A2 ; A2->our palette
LEA pmInfo(A2),A2 ; A2->first colorInfo
;Walk thru each palette entry and make sure there's an index within tolerance.
CLR.L D7 ; Clear upper bits of D7, for BF ops
CLR.L D4 ; D4 = palette entry number, and flags in high bits
MOVE BlackIndex(A6),D5 ; when looking for indices, start at D5 and work down.
SnagLoop TST ciFlags(A2) ; has this entry been handled?
BMI SnagLoopEnd ; yah.
BTST #TolerantBit,ciUsage+1(A2) ; Is it a tolerator?
BEQ SnagLoopEnd ; nah.
MOVE ciTolerance(A2),D6 ; get tolerance, for later
CMPI #33,Tolerators(A6) ; If a smallish number of tolerators,
BLT.S CheckColor ; Take slow C2I case.
BTST #31,D4 ; Until one entry missed, take slow C2I case.
BEQ.S CheckColor
CMP #$400,D6 ; if tol<$400, just find one (instead of lots of color-to-indexes with new itables)
BLS.S GrabIndex ; Go grab it.
CheckColor SUBQ #4,SP ; space for Color2Index result
PEA ciRGB(A2) ; push pointer to rgb
_Color2Index
MOVE.L (SP)+,D7 ; D7 = closest match
SUBQ #2,SP ; DeltaRGB result
PEA ciRGB(A2) ; Push palette's rgb
PEA ctTable+rgb(A3,D7*8) ; Push closest-match rgb
bsr.l DeltaRGB
CMP (SP)+,D6 ; Compare delta to ciTolerance
BHS.S SnagIt ; Low enough, just mark it handled and go on to take index.
BFTST availBits(A6){D7:1} ; Out of range, but is it owned?
BEQ.S YankIt ; If not, we'll take that entry.
;We must find an index to yank to our color.
GrabIndex SUBQ #2,SP
BSR GimmeIndex ; Get the next available index
MOVE (SP)+,D7 ; D7 = next so-called available index
BEQ.S GoHome ; Zero means we're out of entries
BFTST availBits(A6){D7:1} ; Have we already matched to it?
BNE.S GrabIndex ; If so, we can't just use it.
PillIt MOVE D7,-(SP) ; Pillage this entry
JSR Pillage
YankIt LEA ctTable(A3,D7*8),A0 ; A0->colorSpec we're grabbing
MOVE.L ciRGB+red(A2),rgb+red(A0) ; Yank our index's red,green
MOVE ciRGB+blue(A2),rgb+blue(A0) ; Yank our index's blue
BSET #ctTolBit,value(A0) ; Mark it as tolerance-yanked
SUB #4,SP ; space for result
_GetCTSeed ; put new seed
MOVE.L (SP)+,ctseed(A3) ; into table
ADDQ #1,updates(A6) ; We've made changes
BSET #31,D4 ; We've made changes anyway, we can snag quickly.
SnagIt BFSET availBits(A6){D7:1} ; Mark this index as taken
SnagLoopEnd ADD #ciSize,A2 ; Bump A2 to next colorinfo
ADDQ #1,D4 ; Advance D4 to next entry
CMP myEntries(A6),D4 ; Done yet?
BNE SnagLoop
GoHome MOVE.L DevCTab(A6),A0 ; Get handle
_HUnlock ; Release it
Leave MOVEM.L (SP)+,D3-D7/A2-A3
RTS
;---------------------------------------------------
;
; PROCEDURE DisposeAppPalettes();
;
; Look through the palette list and dispose of any in the current App heap.
DisposeAppPalettes PROC EXPORT
MOVEM.L A0-A3/D0-D3,-(SP) ; save all registers
MOVE.L PMgrHandle,A2 ; get paletteMgr handle
CMP.L MinusOne,A2 ; is it there?
BEQ GoHome ; => no, just return
MOVE.L (A2),A1 ; point to data structure
MOVE.L PListHandle(A1),A0 ; get handle to palette list
_HLock ; and lock it down
MOVE.L (A0),A3 ; point to palette list
Move APalettes(A1),D3 ; get number of active handles
Beq.s NoPals ; no friends => go home
Add FreeSpaces(A1),D3 ; calculate total number of entries
;<13> Clr.L WindowList ; clear the list of windows for FrontWindow AWC.PB506
BRA.S FindEnd ; => check for no entries
FindLoop Move.L PaletteRef(A3),D1 ; get first entry
BEQ.S FindNext ; => no palette in entry
MOVE.L ApplZone,A0 ; get application heap zone <41>
CMP.L A0,D1 ; Are we before the heap zone? <41>
BLO.S FindNext ; Yes => not in app heap
CMP.L bklim(A0),D1 ; Are we past the heap zone <41>
BHS.S FindNext ; => not in app heap
MOVE.L D1,-(SP) ; push palette handle
_DisposePalette ; and dispose it in place
FindNext AddQ #PLstEntrySz,A3 ; bump to the next entry
FindEnd DBra D3,FindLoop ; repeat for all spaces
NoPals MOVE.L (A2),A1 ; point to palette stuff
MOVE.L PListHandle(A1),A0 ; get handle to palette list
_HUnlock ; and unlock it
GoHome Clr.L AppPalette ; set us up for the next guy AWC.PB508
MOVEM.L (SP)+,A0-A3/D0-D3
RTS
;---------------------------------------------------
;
; PROCEDURE DevSetEntries(aGDev:GDeviceHandle);
;
; Pass a gDev handle in A0. A SetEntries is made with the device's own color table.
; The device's seed isn't changed, though.
DevSetEntries PROC EXPORT
MOVE.L A2,-(SP) ; save one register
MOVE.L TheGDevice,-(SP) ; save current gDev
MOVE.L (A0),A2 ; A2->gDev
MOVE.L gdPMap(A2),A2 ; A2 = pixmapH
MOVE.L (A2),A2 ; A2->pixmap
MOVE.L pmTable(A2),A2 ; A2 = cTabH
MOVE.L (A2),A2 ; A2->colortable
MOVE.L ctSeed(A2),-(SP) ; save seed til after SetEntries
MOVE.L A0,TheGDevice ; set to our important one
Clr -(SP) ; push starting count of 0 for SetEntries
Move ctSize(A2),-(SP) ; push number of entries-1
Pea ctTable(A2) ; push address of the first ColorSpec
_SetEntries ; do it
MOVE.L (SP)+,ctSeed(A2) ; restore seed
MOVE.L (SP)+,TheGDevice ; restore gDev
MOVE.L (SP)+,A2 ; restore register
RTS
;---------------------------------------------------
;
; PROCEDURE DisposePalette(srcPalette: PaletteHandle); INLINE $AA93;
;
DisposePalette PROC EXPORT
ParamSize equ 4 ; total bytes of params
srcPalette equ ParamSize+8-4 ; PaletteHandle to dispose
VarSize equ 0
Link A6,#VarSize ; build stack frame
Move.L A2,-(SP) ; save registers
Move.L srcPalette(A6),A2 ; get the handle
CmpA.L #Nil,A2 ; is it nil?
Beq.S GoHome ; yes => go home
Move.L A2,-(SP) ; push handle
Jsr ClearPalette ; release any animating entries
Bne.S GoHome ; if nonzero the palette was bad AWC.PB457
Move.L A2,-(SP) ; push it again
Jsr ErasePalette ; erase palette from PMgrHandle and its window
Move.L A2,A0 ; fetch palette handle into A0
_DisposHandle
GoHome MOVE.L (SP)+,A2 ; restore register
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; FUNCTION GetClut(aGDev:gDeviceHandle):handle; Local;
;
; return a handle of an appropriate default clut for the device passed.
; This'll be unlocked, purgeable.
PROC
EXPORT GetClut
GCVars RECORD {A6Link},DECREMENT
result DS.B 4 ;Result: Handle to clut
aGDev DS.B 4 ;Input: device handle
return DS.B 4
A6Link DS.B 4 ;old contents of A6
oldZone DS.B 4 ;zone, upon entering
typeNumber DS.B 2
linkSize DS.B 0 ;linky number
ENDR
whichClut DC.B 0,1,2,3,4,0,0,5,6 ; Which cluthandle to use
; depth 1 2 2 4 4 8 8
; color? x n y n y n y
clutIDs DC.B $01,$22,$42,$24,$44,$28,$08
WITH GCVars
GetClut LINK A6,#linkSize
MOVEM.L A0-A1/D0-D3,-(SP)
_GetZone ; Save old heap zone,
MOVE.L A0,oldZone(A6) ; To restore upon exit.
MOVE.L SysZone,A0
_SetZone ; But we'll use the system heap.
MOVE.L aGDev(A6),A0
MOVE.L (A0),A0
MOVE.L gdPMap(A0),A1
MOVE.L (A1),A1
MOVE pmPixelSize(A1),D0
CMPI #1,D0 ; one bit?
BEQ.S @bw ; can only be black&white
BTST #0,gdFlags+1(A0) ;A color device?
BEQ.S @bw ; no? pixelSize is good enough
ADDQ #1,D0
@bw LEA whichClut-1,A1 ; A1->which cluthandle to use
MOVE.B (A1,D0.W),D0 ; Get byte sized offset, D0 hibits clr
MOVE D0,typeNumber(A6) ; save number 0-6 for clut type
MOVE.L PMgrHandle,A0 ; A0 = the big handle
MOVE.L (A0),A0 ; A0->PMgr
MOVE.L sevenCluts(A0,D0*4),A0 ; A0 = old Handle for this spot
MOVE.L A0,D1 ; Is it NIL?
BEQ.S @getCTab ; Yes, we'll have to get one
MOVE.L (A0),D1 ; Is it Purged?
BEQ.S @tossAndGet ; Yes => lose old handle, get new one
MOVE.L A0,result(A6) ; No => we had the last one we made
BRA.S @nilResult ; we'll return it.
@tossAndGet _DisposHandle
MOVE typeNumber(A6),D0
@getCTab LEA clutIDs,A0 ; A0->table of clut resource ID's
CLR.L D3 ; Zap upper bytes
MOVE.B (A0,D0.W),D3 ; Get byte-sized morsel into D0, high bits clear
SUBQ #4,SP ; Room for result
MOVE D3,-(SP) ; Push resource ID
_GetCTable
MOVE.L (SP)+,A0 ; Handle in A0
MOVE.L A0,result(A6) ; Get that result into our result
BEQ.S @nilResult ; Problem?
MOVE.L (A0),A1 ; A1->our new clut
CMP.L ctSeed(A1),D3 ; Does the seed match the ID?
BNE.S @purgeIt ; No=>can't be a ROM resource
SUBQ #4,SP
MOVE.L #'clut',-(SP)
MOVE D3,-(SP)
MOVE.L A0,D3 ; We'll keep old one in D3 a moment
MOVE #$FFFF,RomMapInsert
_Get1Resource ; Get only a ROMish version of clut-D3
MOVE.L (SP)+,D2 ; Get anything?
BEQ.S @useOld ; No=>go deal with old one
MOVE.L D2,result(A6) ; Yes=>save this one,
MOVE.L D3,A0 ; lose the old one
_DisposHandle
BRA.S @gotIt
@useOld MOVE.L D3,A0
@purgeIt _HPurge ; No, so mark it purgeable
@gotIt MOVE.L PMgrHandle,A0 ; And save the handle.
MOVE.L (A0),A0 ; A0->PMgrData
MOVE typeNumber(A6),D0 ; D0 = selection, 0-5
MOVE.L result(A6),sevenCluts(A0,D0*4) ; And save the handle.
@nilResult MOVE.L oldZone(A6),A0 ; Now, restore previous zone.
_SetZone
@goHome MOVEM.L (SP)+,A0-A1/D0-D3
UNLK A6
RTD #result-return-4
;---------------------------------------------------
;
; PROCEDURE InitPalettes; INLINE $AA90;
;
PROC
IMPORT RecordPalette,CHECKALLDEVICECLUTS
IMPORT SCATTERDEVICES,UpdateDevices
EXPORT InitPalettes
EXPORT SysColors,SysColorEnd
SysColorCount EQU 2
SysColors DC.W $0000,$0003,$0000,$000F ; seed [long], transIndex [word], ctSize [word]
DC.W $0000,$FFFF,$FFFF,$FFFF ; white
DC.W $0001,$0000,$0000,$0000 ; black
SysColorEnd EQU *
VarSize equ 0
InitPalettes
Link A6,#VarSize ; build stack frame
MoveM.L D3-D4/A2-A4,-(SP) ; save registers
; Start by running down the device list, finding all active CLUT devices. Count how many
; there are and record them in PListHandle.
Move.L PMgrHandle,D0 ; get the Palette Manager handle
Cmp.L #PMgrNil,D0 ; is it nil?
Bne ChkAppPltt ; we're initializaed - check for AppPalette AWC.PB520
; To start things up, allocate enough room for static Palette Manager data and 32 device table
; slots. Note that the current implementation of Color Quickdraw (not the architecture) sets
; a limit on the color index model of 256 entries. THIS NUMBER IS ASSUMED BY THE CODE BELOW,
; but the structure will allow modification once 'clut's bigger than 256 entries are allowed.
; This code also assumes that the cards have the potential of being 256 entry cards even if
; set at a lower resolution, so it always allocates 256 entries in each device map (integer sized).
; Note - the total space allocated for pm device table space is presumed (below) to
; be long word aligned. See the loop below at Clearing.
Move.L #PMgrDataSz,D4 ; set D4 to the required size AWC.PB500
Move.L D4,D0 ; copy size to D0
_NewHandle ,SYS,CLEAR ; allocate our data area in the system heap
Bne GoHome ; we got an error, so we quit
Move.L A0,A3 ; copy to A3 for later use
Move.L A0,PMgrHandle ; and remember it in low memory
MoveQ #0,D3 ; zero our device count
Move.L (A3),A4 ; dereference PMgrHandle
CLR.L scatterDevs(A4) ; no devices needing scatter, to start <dvb3>
CLR.L updateDevs(A4) ; no devices needing scatter, to start <dvb3>
AddA #DevHandles,A4 ; point A4 at our local device list
Clr.L -(SP) ; push room for device handle AWC.PB500
_GetDeviceList ; get the start of the device list AWC.PB500
Move.L (SP)+,A2 ; put the device list in A2 AWC.PB500
Bra.S DeviceEnd ; jump to the end of the loop AWC.PB500
DeviceLoop Move.L (A2),A0 ; dereference device handle
Move gdFlags(A0),D0 ; get flags; is it an active device?
; Bpl.S NextDevice ; no => examine next device ;Yes, we do. <dvb>
BTst #ScreenDevice,D0 ; is it a screen device?
Beq.S NextDevice ; no => examine next device AWC.PB377
; three lines commented out: we list non-cluts in case they become clut. dvb1
; Move gdType(A0),D0 ; get the type of the device AWC.PB377
; Cmp #ClutType,D0 ; is it a Clut device?
; Bne.S NextDevice ; no => we only track Clut devices
AddQ #1,D3 ; yes => bump our device count by 1
Move.L A2,DevHandle(A4) ; copy device handle AWC.PB500
Clr.L DevFrontMost(A4) ; clear device FrontMost field
AddQ #DevInfoSz,A4 ; bump A4 to the next device slot
Add.L #256*PmDevSz,D4 ; each device table is 1024 bytes (for now)
Cmp #DevLimit,D3 ; are we at the limit the PMgr can handle? AWC.PB500
Bpl.S EnoughDevs ; if so, we'll ignore any remaining devices
NextDevice Move.L gdNextGD(A0),A2 ; grab next device AWC.PB500
DeviceEnd Move.L A2,D0 ; CmpA #Nil,A2; is it nil? AWC.PB500
Bne.S DeviceLoop ; no => let's do it again
EnoughDevs Move.L (A3),A4 ; redereference PMgrHandle
Move D3,nDevs(A4) ; save length of device list
Move D3,D0 ; make a copy of D3
Bne.S SeedSizeOk ; make sure we have a minimum size seed AWC.PB500
AddQ #1,D0 ; a kludge, but it's easier this way AWC.PB500
SeedSizeOk Lsl #2,D0 ; multiply by 4 AWC.PB500
Move D0,SeedHSize(A4) ; save size of SeedHSize handle
Clr APalettes(A4) ; no animating palettes yet
Move #ListSpace,FreeSpaces(A4) ; 16 free slots; we'll add more if needed
Move.L D4,D0 ; D4 is the required size of PMgrHandle
Move.L A3,A0 ; put handle in A0 for the call
_SetHandleSize ; and expand the handle up
Bne.S ResizeFails ; it went badly
Move.L #ListSpace,D0 ; start with initial space for handles
Lsl #3,D0 ; multiply by 8
_NewHandle SYS,CLEAR ; allocate and clear the handle
Beq.S ClearAll ; if it works, continue
Move.L A3,A0 ; prepare to dispose the handle
_DisposHandle ; get rid of it
ResizeFails Move.L #PMgrNil,PMgrHandle ; it didn't work - zero the handle
Bra GoHome ; head home with error in D0 AWC.PB508
ClearAll Move.L (A3),A4 ; redereference PMgrHandle
Move.L A0,PListHandle(A4) ; save the list of handles
Move.L A3,A0 ; put PMgrHandle into A0
_HLock ; lock it down
MOVE.L (A3),A4 ; redereference
LEA sevenCluts(A4),A0 ; A0->list of depth-cluts
MOVEQ #6,D0 ; A loop counter
@sclclr CLR.L (A0)+ ; Clear one handle
DBRA D0,@sclclr
Move D3,D0 ; get the number of devices
Lsl #8,D0 ; multiply by 1024/4 (1024 per device/4 per CLR.L)
Lea PMgrDataSz(A4),A0 ; calculate start of device links
Bra.S ClearEnd ; jump into loop
ClearLoop Clr.L (A0)+ ; clear a long word - see! long word aligned
ClearEnd DBra D0,ClearLoop ; repeat for all long words
Move.L theZone,-(SP) ; save the current zone
Move.L SysZone,theZone ; set the system zone
Clr.L -(SP) ; clear some space for a handle
Clr -(SP) ; push PaletteId = 0
_GetNewPalette ; try to get the system palette
Move.L (SP)+,SysPalette(A4) ; save it; was it nil?
Bne.S NoError ; no => we're done
Lea SysColors,A0 ; get a pointer to our default table
Move.L #SysColorEnd-SysColors,D0 ; get size
_PtrToHand ; make a handle out of it
Move.L A0,D3 ; save it
Clr.L -(SP) ; space for result
Move #SysColorCount,-(SP) ; push the number of entries
Move.L A0,-(SP) ; push our handle
Move #pmCourteous,-(SP) ; all courteous entries
Move #$0000,-(SP) ; reasonably tolerant entries, too
_NewPalette ; let's call ourselves to get a new palette
Move.L (SP)+,SysPalette(A4) ; save the palette; we sure hope we got one
Move.L D3,A0 ; put handle back in A0
_DisposHandle ; snuff it
NoError Move.L SysPalette(A4),A0 ; get the palette for a moment
CmpA.L #Nil,A0 ; is there one?
Beq.S Cleanup ; no => cleanup
Move.L (A0),A0 ; dereference SysPalette
BSet #CForeBit,pmPrivate(A0) ; set the system update bits
BSet #CBackBit,PmPrivate(A0)
Cleanup Move.L (SP)+,theZone ; restore the current zone
Move.L A3,A0 ; get PMgrHandle
_HUnlock ; unlock it
JSR CheckAllDeviceCluts ; Let PMgr slam the device cluts
MOVE #$1,-(SP) ; Set the palette with new colors
JSR ScatterDevices ; Redistribute them clut indices
Clr.L AppPalette ; clear the applications's palette AWC.PB457
Bra.S LookForIt ; jump ahead AWC.PB520
; Notice that we rely upon AppPalette being initialized (or -1) every time we arrive here. If
; it is non-zero, we assume this is an extra call to InitPalettes so we just leave.
ChkAppPltt Move.L AppPalette,D0 ; fetch AppPalette; is it nil? AWC.PB520
Beq.S LookForIt ; yes => look for a palette resource 0 AWC.PB508
AddQ.L #1,D0 ; bump it by 1; was it $FFFFFFFF? AWC.PB508
Bne ChkAppPEnd ; no => must be good; next thing AWC.PB520
CLR.L AppPalette ; clear the AppPalette AWC.PB508
LookForIt Tst CurApRefNum ; are we using the system resource file? AWC.PB469
Beq.S ChkAppPEnd ; yes => forget installing an AppPalette AWC.PB520
Clr -(SP) ; function result AWC.PB457
_CurResFile ; get the current resfile AWC.PB457
Move (SP)+,D3 ; put it in D3 AWC.PB457
Cmp CurApRefNum,D3 ; need we change it? AWC.PB457
Beq.S ResFileOkay ; no => we've already got it AWC.PB457
Move CurApRefNum,-(SP) ; push the refnum back AWC.PB457
_UseResFile ; use this resfile AWC.PB457
Clr -(SP) ; result word AWC.PB506
_ResError ; see if this worked AWC.PB506
Move (SP)+,D0 ; get the result AWC.PB506
Bne.S ChkAppPEnd ; quit if we didn't get it AWC.PB520
ResFileOkay Clr.L -(SP) ; function result AWC.PB457
Move.L #'pltt',-(SP) ; push the resource type AWC.PB457
Clr -(SP) ; id 0 AWC.PB457
_Get1Resource ; fetch an application palette, if any AWC.PB457
Move.L (SP)+,A2 ; get handle off the stack AWC.PB457
Move.L A2,D0 ; CmpA.L #Nil,A2; did we get a resource? AWC.PB457
Beq.S Cleanup2 ; if nil we go home AWC.PB457
Move.L A2,-(SP) ; push it for the DetachResource AWC.PB457
_DetachResource ; disconnect from resource manager AWC.PB457
Move.L (A2),A0 ; dereference palette AWC.PB457
Move #AllUpdates,D1 ; set D1 to the default AWC.PB457
Move plttUpdates(A0),D0 ; get update bits AWC.PB457
Bpl.S NoResUpdate ; the user didn't specify any AWC.PB457
ADD D0,D0 ; put the bits in the correct place AWC.PB457
Move D0,D1 ; put the result into D1 AWC.PB457
NoResUpdate Move D1,pmPrivate(A0) ; put them in the correct place AWC.PB457
Move.L A2,-(SP) ; push palette for the RecordPalette AWC.PB457
Jsr RecordPalette ; allocates seeds handle, records palette AWC.PB457
Bne.S Cleanup2 ; it disposed palette if failed AWC.PB457
Move.L A2,AppPalette ; copy it to AppPalette AWC.PB457
Move.L (A2),A0 ; dereference AppPalette AWC.PB457
BSet #DisposeBit,pmPrivate(A0) ; set for automatic disposal AWC.PB457
Clr.L pmDevices(A0) ; clear device bitmap AWC.PB457
Cleanup2 Cmp CurApRefNum,D3 ; did we change the current resfile? AWC.PB457
Beq.S ChkAppPEnd ; no => don't put it back AWC.PB457
Move D3,-(SP) ; push the old current resfile AWC.PB457
_UseResFile ; and restore the old one AWC.PB457
ChkAppPEnd
CheckExit
JSR UpdateDevices
GoHome MoveM.L (SP)+,D3-D4/A2-A4 ; restore registers
Unlk A6 ; clear stack frame
Rts ; go home
;---------------------------------------------------
;
; FUNCTION CheckDeviceColors(aGDev:gdHandle):Boolean; LOCAL;
;
; Looks at a (hopefully clut) device, and compare its clut to the
; default clut for that device. If even one entry which is not owned for animation
; is out of place, the whole clut is marked for scattering. Return TRUE if
; the device is now marked for scattering.
CheckDeviceColors PROC EXPORT
CDCVars RECORD {A6Link},DECREMENT
result DS.B 2 ;Result: boolean
aGDev DS.B 4 ;Input: device handle
return DS.B 4
A6Link DS.B 4 ;old contents of A6
linkSize DS.B 0 ;linky number
ENDR
WITH CDCVars
LINK A6,#linkSize
MOVEM.L A0-A3/D0-D2,-(SP)
CLR D2 ; D2 = on-the-fly bool result.
MOVE.L aGDev(A6),A2
MOVE.L (A2),A3 ; A3->gDevice
TST gdType(A3) ; a clut device? <dvb5>
BNE.S GoHome ; No=> go home w/false
MOVE $14(A3),D0
AND #$8010,D0
BEQ.S GoHome ; No=> ditto
SUBQ #4,SP ; space for result <dvb5>
MOVE.L A2,-(SP) ; push gDevice handle <dvb5>
JSR GetClut ; get the appropriate default clut <dvb5>
MOVE.L (SP)+,A0 ; A0 = handle to default clut, keep handle on stk
MOVE.L (A0),A0 ; A0->default clut <dvb5>
LEA ctTable+rgb(A0),A0 ; bump to first colorSpec's rgb fiel <dvb5>
MOVE.L gdPMap(A3),A1 ; A1 = device's pixmap <dvb5>
MOVE.L (A1),A1 ; A1->device's pixmap <dvb5>
MOVE.L pmTable(A1),A1 ; A1 = device's clut <dvb5>
MOVE.L (A1),A1 ; A1->device's clut <dvb5>
MOVE ctSize(A1),D0 ; D0 = size of clut - 1 <dvb5>
LEA ctTable(A1),A1 ; bump A1 to first colorSpec <dvb5>
iLoop BTST #reserveBit,value(A1) ; is this entry reserved? <dvb5>
BNE.S iLoopEnd ; yes, skip it <dvb5>
BSET #ctMatchBit,value(A1) ; mark entry as looked at
MOVE.L red(A0),D1 ; get default red,green
CMP.L rgb+red(A1),D1 ; do red and green match default? <dvb5>
BNE.S fixIt ; No, scatter all the indices <dvb5>
MOVE blue(A0),D1 ; Get default blue
CMP rgb+blue(A1),D1 ; match device blue? <dvb5>
BEQ.S iLoopEnd ; No, scatter... <dvb5>
fixIt BSET #ctScatterBit,value(A1) ; Mark index for scattering <dvb5>
MOVEQ #-1,D2 ; Set D2 result to true
iLoopEnd ADDA #8,A0 ; Bump A0 to next colorSpec <dvb5>
ADDA #8,A1 ; Bump A1 to next colorSpec <dvb5>
DBRA D0,iLoop ; loop for all indices <dvb5>
GoHome MOVE D2,result(A6) ; Set result.
MOVEM.L (SP)+,A0-A3/D0-D2
UNLK A6
RTD #result-return-4
;---------------------------------------------------
;
; FUNCTION FindLink(LinkInfo:integer):integer; LOCAL;
;
; FindLink searches the device links until it encounters a device that matches Device or
; until it reaches the end of the list. It returns the index if it finds one. It
; returns 0 (which is an illegal index since it matches white) if it can't find one.
FindLink PROC EXPORT
ParamSize equ 2 ; total bytes of params
theIndex equ ParamSize+10-2 ; index result
LinkInfo equ theIndex-2 ; this palette's key to previously reserved entries
VarSize equ 0
Link A4,#VarSize ; build stack frame
Move.L D3,-(SP) ; save a register
; We will use D3 as a watchdog counter. We set it to the maximum number of devices that we
; might have to search so that if things go very wrong we stand a chance of finding out about it.
Clr theIndex(A4) ; set result to "illegal"
Move LinkInfo(A4),D0 ; get link data
BfExtU D0{16:3},D1 ; grab top 3 bits
Cmp #4,D1 ; are they set correctly
Bne.S GoHome ; no => the LinkInfo is invalid
Move Devices(A6),D3 ; get number of devices
Move.L PMgrPtr(A6),A0 ; PMgrHandle^
AddA.L #LinkTabs,A0 ; calculate start of LinkTabs
Bra.S IndexEnd ; start watchdog loop
IndexLoop BfExtU D0{19:5},D1 ; grab device number (0..31)
BfExtU D0{24:8},D2 ; grab index number (0..255)
Cmp CurDevice(A6),D1 ; is it this device?
Beq.S FoundIt ; yes => we've got it
Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Move (A0,D1.L*4),D0 ; get next link; is the top bit set?
Bpl.S GoHome ; no => stop because we ran out of tries
IndexEnd DBra D3,IndexLoop ; examine another index until our watchdog runs out
; Our watchdog counter ran out, so something is terribly wrong. We'll be polite about it and
; say we were just unable to find it.
Bra.S GoHome
; We found the index. Set true and return the appropriate index to theIndex(A4)
FoundIt And #$00FF,D2 ; clear everything except the index
Move D2,theIndex(A4) ; set the result
GoHome Move.L (SP)+,D3 ; restore registers
Unlk A4 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE AnalyzeDev; LOCAL;
;
; Build, into the InfoPtr, a sequence of entries to steal. The priorities are
; as follows: Any explicit entries are available for explicating. Any free
; entries are first available. Any yanked-tolerant entries are available next.
; Any animated entries owned by other palettes are available last.
; One more thing: the secondary sorting on 1,2,4-bit devices is by index, and on
; 8-bit devices is by nibble-swapped index. Thus, and this is especially
; important on gray-scale cluts, the indices
; will be stolen in a somewhat spread-out manner.
AnalyzeDev PROC EXPORT
MOVEM.L A2-A3/D3-D5,-(SP)
LEA availBits(A6),A2 ; A2->availBits. Permanently.
MOVE.L DevCTab(A6),A3 ; A3 = handle to current dev's clut
MOVE.L (A3),A3 ; A3 -> current dev's clut. Permanently.
CLR.L D3 ; Clear upper bits of D3, for BF op
MOVE BlackIndex(A6),D3 ; D3 = highest index. Permanently.
CLR D4 ; D4 = number of indices put into list.
BSR ClearAvailBits ; Start the bits az nilz.
;
; First, find and unavailable-ize any
; eplicit entries from our palette.
;
MOVE.L PalettePtr(A6),A0 ; A0->our palette
CLR.L D0 ; D0 = each entry number, starting zero
CLR.L D2 ; Clear upper bits of D2, for BF ops
LEA pmInfo(A0),A1
BRA.S @expEnd
@expLoop MOVE ciFlags(A1),D1 ; D1 = usage for the entry
BMI.S @expNext ; Handled-bit->set!
BTST #explicitBit,D1 ; An explicit entry?
BEQ.S @expNext
MOVE D0,D2 ; Copy entry number.
AND D3,D2 ; And it down into clut's range
BFSET (A2){D2:1} ; Set the used bit in our array o' bits
@expNext ADDA #ciSize,A1 ; Bump A1 to next colorinfo
ADDQ #1,D0 ; Bump D0 to match it's index
@expEnd CMP pmEntries(A0),D0 ; Done last one yet?
BLO.S @expLoop ; No, do more.
;
; Add any fully open indices to our list.
;
MOVE.L InfoPtr(A6),A1 ; A1->our list o' entries.
MOVE D3,D0 ; D0 will do our walking
CLR.L D1 ; Clear upper bits of D1, for BF ops
@openLoop MOVE D0,D1 ; D1=our possibly scrambled index
BTST #4,D3 ; 8-bit device?
BEQ.S @openNot8 ; No, don't spread entries
ROR.B #4,D1 ; Yes => swap hi,lo nibbles
@openNot8 BFTST (A2){D1:1} ; This entry already taken?
BNE.S @openNext ; Yes => try next
MOVE ctTable+value(A3,D1*8),D2 ; Get the status of index D1
AND #ctReserveVal+ctTolVal,D2 ; Mask out the bits we need to check
BNE.S @openNext ; Either bit set is a problem, cant use it
BFSET (A2){D1:1} ; Mark it as taken
MOVE D1,(A1,D4*2) ; Put index into list.
ADDQ #1,D4 ; One more in list.
@openNext DBRA D0,@openLoop ; Keep checking, right down to zero.
;
; Add any non-reserved (inanimate) indices to our list.
;
MOVE D3,D0 ; D0 will do our walking
@inAniLoop MOVE D0,D1 ; D1=our possibly scrambled index
BTST #4,D3 ; 8-bit device?
BEQ.S @inAniNot8 ; No, don't spread entries
ROR.B #4,D1 ; Yes => swap hi,lo nibbles
@inAniNot8 BFTST (A2){D1:1} ; This entry already taken?
BNE.S @inAniNext ; Yes => try next
BTST #ctReserveBit,ctTable+value(A3,D1*8) ; This index anim?
BNE.S @inAniNext ; Yes: not for us.
BFSET (A2){D1:1} ; Mark it as taken
MOVE D1,(A1,D4*2) ; Put index into list.
ADDQ #1,D4 ; One more in list.
@inAniNext DBRA D0,@inAniLoop ; Keep checking, right down to zero.
;
; Add any reserved indices which aren't ours to our list.
; This is called Seriously Pillaging.
;
MOVE pmPrivate(A0),D5 ; D5 = palette number plus some bits
AND #pIDMask,D5 ; D5 = palette number.
Move.L PMgrPtr(A6),A0 ; A0 = base pointer
AddA.L #LinkTabs,A0 ; A0->dem linky tings
MOVE D3,D0 ; D0 will do our walking
@pillLoop MOVE D0,D1 ; D1=our possibly scrambled index
BTST #4,D3 ; 8-bit device?
BEQ.S @pillNot8 ; No, don't spread entries
ROR.B #4,D1 ; Yes => swap hi,lo nibbles
@pillNot8 BFTST (A2){D1:1} ; This entry already taken?
BNE.S @pillNext ; Yes => try next
; No=> walk the linktabs, see if it's ours
MOVE CurDevice(A6),D2 ; D2 = device number we're checking
LSL #8,D2 ; Device number in upper bits
MOVE.B D1,D2 ; Index in lower byte
@findOwner AND #$1FFF,D2 ; Clear key bits
MOVE.W foreLink(A0,D2*4),D2 ; Get the forelink
BEQ.S @pillNext
BMI.S @findOwner
AND #$1FFF,D2 ; Okay, clear the key bits
CMP D2,D5 ; Is this index owned by this palette
BEQ.S @pillNext ; Yes: not for us.
BFSET (A2){D1:1} ; Mark it as taken
MOVE D1,(A1,D4*2) ; Put index into list.
ADDQ #1,D4 ; One more in list.
@pillNext DBRA D0,@pillLoop ; Keep checking, right down to zero.
MOVE D4,Pillages(A6) ; This is how many we've got
Clr Histogram(A6) ; This is how many we've used
BSR.S ClearAvailBits ; Clear the bits array to nothing again.
MOVEM.L (SP)+,A2-A3/D3-D5
RTS
ClearAvailBits
MOVEQ #7,D0
@a CLR.L availBits(A6,D0*4)
DBRA D0,@a
BFSET availBits(A6){0:1} ; set the bit for white
BFSET availBits(A6){D3:1} ; set the bit for black
RTS
;---------------------------------------------------
;
; PROCEDURE Pillage(myChoice); LOCAL;
;
; Just clear the links for index myChoice on CurDevice(A6)
; No registers altered.
Pillage PROC EXPORT
PilVars RECORD {A4Link},DECREMENT
result DS.B 0 ;result: none
myChoice DS.B 2 ;input: index to pillage
return DS.B 4
A4Link DS.B 4 ;old contents of A4
linkSize DS.B 0 ;linky number
ENDR
WITH PilVars
LINK A4,#linkSize
MoveM.L D0/D3/D4,-(SP) ; save registers
MOVE myChoice(A4),D3 ; does the caller want a specific index?
MOVE CurDevice(A6),D4
LSL #8,D4 ; shift device into upper bits
MOVE.B D3,D4 ; put index into low bits
MOVE D4,-(SP)
_ZapLinks ; unlink index D3 of CurDevice(A6)
MOVE.L DevCTab(A6),A0 ; A0 = current device's clut
MOVE.L (A0),A0 ; A0->clut
CLR ctTable+value(A0,D3*8) ; Unmark the clut index entirely
GoHome MoveM.L (SP)+,D0/D3/D4 ; restore registers
Unlk A4 ; clear stack frame
Rtd #result-return-4 ; strip parameters and go home
;---------------------------------------------------
;
; FUNCTION GimmeIndex:INTEGER; LOCAL;
;
; Judging from the infohandle, get the next available index. Return
; zero if there's none left. We assume the ActivatePalette stack frame.
; We'll make use of registers D0,D1, and A0.
;
GimmeIndex PROC EXPORT
CLR D1 ; our result
MOVE Histogram(A6),D0 ; D0 = next item from infoptr to steal
CMP Pillages(A6),D0 ; Taken as many as we can?
BEQ.S @goHome ; Return nil.
MOVE.L infoPtr(A6),A0 ; A0->list of indices to take
MOVE (A0,D0*2),D1 ; D1 = next one off list
ADDQ #1,Histogram(A6) ; Bump to next guy
@goHome MOVE D1,4(SP) ; return index
RTS
;---------------------------------------------------
;
; PROCEDURE MarkDevUBit; LOCAL;
;
; Set bit CurDevice in updateDevs.
MarkDevUBit PROC
Move CurDevice(A6),D0 ; get current device
MOVE.L PMgrPtr(A6),A0 ; A1->PMgr data
MOVE.L updateDevs(A0),D1 ; tricky offset, get device update mask
BSET D0,D1 ; set the device's bit for updating
MOVE.L D1,updateDevs(A0) ; put back mask
RTS
IF NOT ROMPaletteMgr THEN
;---------------------------------------------------
;
; FUNCTION DeltaRGB(RGB1,RGB2:RGBColor):integer; LOCAL;
;
; A cool routine which preserves all registers
DeltaRGB FUNC EXPORT
ParamSize equ 8 ; total bytes of params
Delta equ ParamSIze+10-2 ; integer result
RGB1 equ Delta-4 ; palette entry pointer
RGB2 equ RGB1-4 ; color table entry pointer
VarSize equ 0 ; size of variables
Link A6,#VarSize ; build stack frame
MOVEM.L A0-A1/D0-D1,-(SP)
Move.L RGB1(A6),A0 ; get first RGBColor
Move.L RGB2(A6),A1 ; get second RGBColor
Move (A1)+,D0 ; grab index red
Sub (A0)+,D0 ; subtract entry red
Bhs.S NotNeg1 ; take abs(Index.Red-ColorInfo.Red)
Neg D0 ; negate it
NotNeg1 Move (A1)+,D1 ; grab index green
Sub (A0)+,D1 ; subtract entry green
Bhs.S NotNeg2 ; take abs(Index.Green-ColorInfo.Green)
Neg D1 ; negate it
NotNeg2 Cmp D0,D1 ; leave greater unsigned value in D0
Blo.S DontSwitch1 ; D1 < D0 => D0 is already greater
Move D1,D0 ; green value is greater
DontSwitch1 Move (A1),D1 ; grab index blue
Sub (A0),D1 ; subtract entry blue
Bhs.S NotNeg3 ; take abs(Index.Blue-ColorInfo.Blue)
Neg D1 ; negate it
NotNeg3 Cmp D0,D1 ; leave greater unsigned value in D0
Blo.S FixResult ; D1 < D0 => D0 is already greater
Move D1,D0 ; blue value is greater
FixResult Move D0,Delta(A6) ; set result
MOVEM.L (SP)+,A0-A1/D0-D1
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
ENDF
ENDIF
;---------------------------------------------------
;
; PROCEDURE RedrawDesktop; LOCAL;
;
; Ignoring things like "DeskHook"... Just paint the rectangle pointed to by A2 on the desktop.
; We'll use A3 in the process.
RedrawDesktop PROC EXPORT
SUBQ #4,SP ; space for new region
_NewRgn
MOVE.L (SP),A3 ; A3 = new region, leave stack copy
MOVE.L A2,-(SP) ; Push device rectangle
_RectRgn ; Make that rectangular region
CLR.L -(SP) ; NIL = desktop area
MOVE.L A3,-(SP) ; Push the device region
_PaintOne ; Update desktop within device bounds
MOVE.L A3,-(SP) ; Get rid of our temp region
_DisposRgn
RTS
;---------------------------------------------------
;
; PROCEDURE DirtySeeds(dstPalette: PaletteHandle); LOCAL;
;
DirtySeeds PROC EXPORT
ParamSize equ 4 ; total bytes of params
dstPalette equ ParamSize+8-4 ; destination Palette handle
VarSize equ 0 ; size of variables
Link A6,#VarSize ; build stack frame AWC.PB508
Move.L PMgrHandle,A0 ; get the PMgrHandle (we assume its safe) AWC.PB508
Move.L (A0),A0 ; dereference it AWC.PB508
Move SeedHSize(A0),D0 ; get the seed handle size AWC.PB508
Lsr #2,D0 ; divide it by 4 to get number of longs AWC.PB508
SubQ #1,D0 ; decrement it for the DBra loop AWC.PB508
Move.L DstPalette(A6),A0 ; get the palette AWC.PB508
Move.L (A0),A0 ; dereference it AWC.PB508
BSet #DirtyBit,pmPrivate(A0) ; set the dirty bit AWC.PB508
Move.L pmSeeds(A0),A0 ; get the seeds handle AWC.PB508
Move.L (A0),A0 ; dereference it AWC.PB508
ClearLoop Clr.L (A0)+ ; clear a seed AWC.PB508
DBra D0,ClearLoop ; continue AWC.PB508
GoHome Unlk A6 ; clear stack frame AWC.PB508
Rtd #ParamSize ; strip parameters and go home AWC.PB508
;---------------------------------------------------
;
; PROCEDURE SetPalette(dstWindow: WindowPtr; srcPalette: PaletteHandle; CUpdates: BOOLEAN);
; INLINE $AA95;
;
; Passing -1 for the window sets the App Palette to the palette specified.
SetPalette PROC EXPORT
ParamSize equ 10 ; total bytes of params
dstWindow equ ParamSize+8-4 ; source Palette handle
srcPalette equ dstWindow-4 ; new window, if any
CUpdates equ srcPalette-2 ; whether we want background color updates
VarSize equ 0 ; size of variables
Link A6,#VarSize ; build stack frame
MOVE.L D3,-(SP)
Move.L PMgrHandle,A1 ; we have to be initialized
CmpA.L #PMgrNil,A1 ; is it initialized?
Beq GoHome ; no => punt
Move.L dstWindow(A6),A0 ; get the window pointer
CmpA.L #-1,A0 ; does the caller want to set AppPalette?
Bne.S NotSystem ; no => go look for the window
Move.L AppPalette,D0 ; get the application palette; is it nil? AWC.PB457
Beq.S NoAppPltt ; yes => don't dispose it AWC.PB457
Move.L D0,A0 ; put it in an address register AWC.PB457
Move.L (A0),A0 ; dereference it AWC.PB457
BTst #DisposeBit,pmPrivate(A0) ; should we clobber it? AWC.PB457
Beq.S NoAppPltt ; no => the caller deals with it AWC.PB457
Move.L D0,-(SP) ; push the palette AWC.PB457
_DisposePalette ; can you say "bye bye"? AWC.PB457
NoAppPltt Move.L SrcPalette(A6),A0 ; get the palette parameter AWC.PB457
Move.L A0,AppPalette ; set the layer palette; is it nil? AWC.PB457
Beq.S AppNil ; no => activate the layer palette AWC.PB457
MOVE.L (A0),A0 ; A0->Palette
BSet #CBackBit,PmPrivate(A0) ; set background update bit AWC PB223
BSet #CForeBit,PmPrivate(A0) ; set foreground update bit AWC PB223
Move.L SrcPalette(A6),A0 ; get the palette parameter AWC.PB457
BRA.S AppNotNil
AppNil Move.L (A1),A0 ; dereference PMgrHandle <dvb15 1.8>
Move.L SysPalette(A0),A0 ; get the system palette AWC.PB457
Move.L A0,D0 ; CmpA.L #Nil,A0; is it nil? AWC.PB457
Beq GoHome ; yes => shouldn't happen, but quit anyway AWC.PB457
AppNotNil Move.L A0,-(SP) ; push the palette pointer AWC.PB508
Bsr DirtySeeds ; clear the device seeds so we'll update AWC.PB508
Clr.L -(SP) ; push function result AWC.PB439
_FrontWindow ; push the front window AWC.PB439
Bra.S DontClear ; activate it AWC PB223
NotSystem Tst PortBits+RowBytes(A0) ; is it a new port?
Bpl.S GoHome ; if not, we're out of here
Move.L srcPalette(A6),D0 ; get the palette handle
Move.L GrafVars(A0),A1 ; get handle to GrafVars
Move.L (A1),A1 ; dereference GrafVars
Move.L PmFgColor(A1),D3 ; save whatever's there currently
Move.L D0,PmFgColor(A1) ; store the palette in GrafVars.PmFgColor; is it nil?
Beq.S BitsOkay ; yes => that's okay, but we won't dereference it
Move.L D0,A1 ; put the Palette handle into A1
Move.L (A1),A1 ; dereference it
; Move.L A0,pmWindow(A1) ; store the window in the palette AWC.PB439
BClr #CBackBit,PmPrivate(A1) ; clear background update bit AWC PB223
BSet #CForeBit,PmPrivate(A1) ; set foreground update bit AWC PB223
Tst.B CUpdates(A6) ; does she want background updates? AWC PB223
Beq.S BitsOkay ; 0 => default case, CUpdates = false AWC PB223
Bpl.S AllowBacks ; 1 => CUpdates = true AWC PB223
BTst #NForeBit,CUpdates(A6) ; does he want foreground updates? AWC PB223
Bne.S YesFores ; yes => leave it as is AWC PB223
BClr #CForeBit,PmPrivate(A1) ; turn foreground updates off AWC PB223
YesFores BTst #NBackBit,CUpdates(A6) ; does she want background updates? AWC PB223
Beq.S BitsOkay ; no => skip it AWC PB223
AllowBacks BSet #CBackBit,PmPrivate(A1) ; set the foreground update bit AWC PB223
BitsOkay Cmp.L D0,D3 ; are they identical? AWC PB223
Beq.S GoHome ; don't bother activating anything
Move.L A0,-(SP) ; push the window pointer for the activate palette
Tst.L D3 ; is this nil?
Beq.S DontClear ; don't clear it
MOVE.L D3,-(SP)
JSR UpdatePalette ; Get rid of reserved entries, if necessary
Move.L D3,A0 ; copy it to an address register AWC.PB457
Move.L (A0),A0 ; dereference it AWC.PB457
BTst #DisposeBit,pmPrivate(A0) ; should we dispose it? AWC.PB457
Beq.S DontClear ; no => leave it alone AWC.PB457
Move.L D3,-(SP) ; push the old handle
_DisposePalette ; can you say "bye bye"? I knew you could AWC.PB457
DontClear _ActivatePalette ; set the palette if it happens to be FrontWIndow
GoHome MOVE.L (SP)+,D3
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; FUNCTION GetPalette(srcWindow: WindowPtr) : PaletteHandle; INLINE $AA96;
;
GetPalette PROC EXPORT
ParamSize equ 4 ; total bytes of params
GetResult equ ParamSize+12-4 ; result palette handle
srcWindow equ GetResult-4 ; source window to help find the palette
VarSize equ 0 ; size of variables
Link A6,#VarSize ; build stack frame
Clr.L GetResult(A6) ; clear the result handle
Move.L PMgrHandle,A1 ; we have to be initialized
CmpA.L #PMgrNil,A1 ; is it initialized?
Beq.S GoHome ; no => punt
Move.L srcWindow(A6),A0 ; get the window pointer
CmpA.L #Nil,A0 ; is it real?
Beq.S GoHome ; no => punt
CmpA.L #-1,A0 ; do they want the system palette?
Bne.S NotSystem ; no, not the system
Move.L AppPalette,GetResult(A6) ; grab AppPalette; is it nil? AWC.PB457
Bne.S GoHome ; no => we're done AWC.PB457
Move.L (A1),A1 ; dereference PMgrHandle AWC.PB457
Move.L SysPalette(A1),A0 ; get SysPalette AWC.PB457
Move.L A0,D0 ; CmpA.L #Nil,A0; is it nil? AWC.PB457
Beq.S GoHome ; yes => how did this happen? oh well, quit AWC.PB457
_HandToHand ; make a copy of it AWC.PB457
Tst D0 ; did the call succeed? AWC.PB457
Bne.S GoHome ; no => go home with result nil AWC.PB457
Move.L A0,AppPalette ; now we'll use the copy AWC.PB457
Move.L A0,GetResult(A6) ; give them the copy's handle AWC.PB457
Move.L A0,-(SP) ; push the handle for RecordPalette AWC.PB457
Move.L (A0),A0 ; dereference it AWC.PB457
Clr.L pmSeeds(A0) ; kill the copy of the seeds handle AWC.PB457
BClr #DisposeBit,pmPrivate(A0) ; caller must now dispose it AWC.PB457
Jsr RecordPalette ; insert it into our list of known things AWC.PB457
Beq.S GoHome ; scurry out of here AWC.PB457
Clr.L AppPalette ; sorry, it failed AWC.PB457
Clr.L GetResult(A6) ; so clear the result, too AWC.PB457
Bra.S GoHome ; continue AWC.PB457
NotSystem Tst PortBits+RowBytes(A0) ; is it a new port?
Bpl.S GoHome ; if not, we're out of here
Move.L GrafVars(A0),A0 ; get handle to GrafVars
Move.L (A0),A0 ; dereference GrafVars
Move.L PmFgColor(A0),A0 ; get the palette AWC.PB457
Move.L A0,GetResult(A6) ; give it to the caller; is it nil? AWC.PB457
Beq.S GoHome ; yes => don't bother with the dispose flag AWC.PB457
Move.L (A0),A0 ; dereference it AWC.PB457
BClr #DisposeBit,PmPrivate(A0) ; turn off the auto dispose AWC.PB457
GoHome Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE FindIndex; IMMEDIATE;
;
; On entry:
; A2 - Palette pointer
; A3 - ColorInfo
;
; On exit:
; D0 - index of animating entry; 0 if not found (0 is illegal for animation)
FindIndex PROC EXPORT
MoveM.L D3/D4,-(SP) ; save registers
Move ciPrivate(A3),D0 ; get link info
BfExtU D0{16:3},D1 ; grab top 3 bits
Cmp #4,D1 ; are they set correctly
Bne.S BadIndex ; no => the LinkInfo is invalid
Move.L PMgrHandle,A0 ; get main handle
CmpA.L #PMgrNil,A0 ; is it nil?
Beq.S BadIndex ; yes => punt
Move.L (A0),A0 ; dereference the palette manager
Move nDevs(A0),D3 ; get number of devices to search in D3
Beq.S BadIndex ; no devices => can't animate AWC.PB500
Lea DevHandles(A0),A1 ; point A1 at the device info stuff
Bra.S DevEnd ; jump into loop
DevLoop Move.L DevHandle(A1,D3.W*8),D4 ; get device handle
Cmp.L theGDevice,D4 ; is this it?
Beq.S FoundDevice ; yes => continue
DevEnd DBra D3,DevLoop ; no => look at another device
Bra.S BadIndex ; we fell through - punt
FoundDevice Move nDevs(A0),D4 ; get number of devices, this time as a watchdog
AddA.L #LinkTabs,A0 ; bump A0 to the base of LinkTabs
Bra.S IndexEnd ; start watchdog loop
IndexLoop BfExtU D0{19:5},D1 ; grab device number (0..31)
BfExtU D0{24:8},D2 ; grab index number (0..255)
Cmp D3,D1 ; is it this device?
Beq.S FoundIndex ; yes => we've got it
Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Move ForeLink(A0,D1.L*4),D0 ; get next link; is the top bit set?
Bpl.S BadIndex ; no => stop because we ran out of tries
IndexEnd DBra D4,IndexLoop ; examine another index until our watchdog runs out
BadIndex Bra.S SetBadIndex ; set index to "illegal" AWC.PB377
; We found the index. Ensure that we don't exceed the bit depth, set "true" by returning
; a value <> 0.
FoundIndex And #$00FF,D2 ; clear everything except the index
Move D2,D0 ; set the result AWC.PB377
Move.L theGDevice,A0 ; get theGDevice AWC.PB377
Move.L (A0),A0 ; dereference it AWC.PB377
Move.L gdPMap(A0),A0 ; get handle to pixmap AWC.PB377
Move.L (A0),A0 ; dereference pixmap AWC.PB377
Move.L pmTable(A0),A0 ; get handle to CTab AWC.PB377
Move.L (A0),A0 ; dereference color table AWC.PB377
Cmp ctSize(A0),D0 ; compare link to maximum index AWC.PB377
Blt.S GoHome ; if D0-ctSize <= 0 then cool AWC.PB480
SetBadIndex MoveQ #0,D0 ; set index to "illegal" white AWC.PB377
GoHome MoveM.L (SP)+,D3/D4 ; restore registers
Rts ; go home
;---------------------------------------------------
;
; FUNCTION Entry2Index(srcEntry: INTEGER):LONGINT; AAA2/0
;
; Return long index of specified entry of thePort's palette, on theGDevice.
; If none, return black, and return a QDErr.
; Mostly, rely on Color2Index to do the picking for us. We'll override its
; choice for an animated or explicit entry on an appropriate device.
Entry2Index PROC EXPORT
EIVars RECORD {A6Link},DECREMENT
result DS.B 4 ;Result: Longword index
srcEntry DS.B 2 ;Input: entry in palette of current port
return DS.B 4
A6Link DS.B 4 ; old contents of A6
srcPalette DS.B 4 ; The palette we're working on.
linkSize DS.B 0 ; linky number
ENDR
WITH EIVars
LINK A6,#linkSize
MoveM.L A2-A3,-(SP) ; save registers
MOVE #1,QDErr ; Default: error
CLR.L result(A6) ; Default: white. Or maybe black.
Move.L PMgrHandle,D0 ; get the main handle, are we initialized?
Beq GoHome ; no => punt AWC.PB377
Move.L GrafGlobals(A5),A0 ; get the QuickDraw globals pointer
Move.L ThePort(A0),A0 ; point at the port
Tst PortBits+Rowbytes(A0) ; is it a new port?
Bpl GoHome ; no => punt AWC.PB377
Move.L GrafVars(A0),A0 ; get the data handle
Move.L (A0),A0 ; dereference it
Move.L PmFgColor(A0),A2 ; get the palette handle (finally)
Move.L A2,D0 ; CmpA.L #Nil,A2; is there a palette? AWC.PB508
Bne.S FoundAPltt ; yes => we're cool so far AWC.PB508
Move.L AppPalette,A2 ; grab the AppPalette for use AWC.PB508
Move.L A2,D0 ; CmpA.L #Nil,A2; is there an AppPalette AWC.PB508
Beq GoHome ; no => punt AWC.PB508
FoundAPltt Move.L A2,srcPalette(A6) ; save it so we can unlock it AWC.PB520
Move.L A2,A0 ; put the handle into A0 AWC.PB520
_HLock ; lock it down AWC.PB520
Move.L (A2),A2 ; dereference myPalette AWC.PB508
MoveQ #0,D0 ; clear the high word
Move srcEntry(A6),D0 ; capture the index
Cmp pmEntries(A2),D0 ; D0 - pmEntries; is myEntry out of range?
Bhs UnlockPltt ; yes, so we quit AWC.PB520
Asl.L #4,D0 ; multiply by record size of 16
Lea pmInfo(A2,D0.L),A3 ; set A3 to entry's ColorInfo
CLR.L -(SP) ; Make room for result <dvb7>
Pea ciRGB(A3) ; push address of ciRGB field
BTST #animatedBit,ciUsage+1(A3) ; an animated entry? <dvb11>
BEQ.S @notAn ; No=>plain color2Index <dvb11>
ADDQ.L #1,(SP) ; Yes => use RGB from lo-bytes of ciRGB <dvb11>
@notAn _Color2Index ; Get that index <dvb7>
MOVE.L (SP)+,result(A6) ; Use that, if nothing else goes well. <dvb7>
CLR QDErr ; Well, we got something. <dvb7>
Move.L theGDevice,A0 ; get theGDevice
Move.L (A0),A0 ; dereference it
MOVE.L gdPMap(A0),A1 ; A1 = Pixmap H
MOVE.L (A1),A1 ; A1 -> pixmap
CMPI #2,pixelSize(A1) ; 1 or two bits deep?
BGT.S @b ; No=>don't check pmWhite/Black
MOVE ciUsage(A3),D1 ; D1 = usage
BTST #whiteBit,D1 ; go White on 1-2 bits?
BEQ.S @notWhite ; No=>try black
CLR D0 ; Yes=>result color is white.
BRA.S ShoveIndex
@notWhite BTST #blackBit,D1 ; go Black on 1-2 bits?
BEQ.S @a ; No=>check for animated/explicit stuff
MOVEQ #-1,D0 ; Yes=>Set all the bits for the index
BRA.S inRange ; and trim it to max allowed.
@b
MOVE gdType(A0),D1 ; get the type <dvb12>
BEQ.s @a ; is it a clut device? <dvb12>
SUBQ #1,D1 ; fixed type? <dvb12>
BNE.S UnlockPltt ; no => we're almost done <dvb3>
@a MOVE $14(A3),D0
AND #$8010,D0
BEQ.S UnlockPltt
Move ciUsage(A3),D1 ; get flags
MoveQ #0,D0 ; clear high word
Move srcEntry(A6),D0 ; set D0 in case it is an explicit index
BTst #AnimatedBit,D1 ; no => test animation bit
Beq.S checkExplct ; if not, maybe explicit AWC.PB520
Jsr FindIndex ; uses our registers - put reserved index in D0
Tst D0 ; was the result "white"?
Beq.S UnlockPltt ; yes => give up
Bra.S ShoveIndex ; share common code
checkExplct BTST #ExplicitBit,D1 ; <dvb4>
BEQ.S UnlockPltt ; <dvb4>
BTST #TolerantBit,D1 ; If we're explicit+tolerant, go with Color2Index.
BNE.S UnlockPltt ; After all, ActivatePalÉ tried to get it for us.
inRange
Move.L gdPMap(A0),A0 ; get handle to pixmap
Move.L (A0),A0 ; dereference pixmap
Move.L pmTable(A0),A0 ; get handle to CTab
Move.L (A0),A0 ; dereference color table
And ctSize(A0),D0 ; and D0 with maximum index
ShoveIndex Move.L D0,result(A6) ; jam the index AWC.PB377
UnlockPltt Move.L SrcPalette(A6),A0 ; get whichever palette we used AWC.PB520
_HUnlock ; unlock it AWC.PB520
GoHome MoveM.L (SP)+,A2-A3 ; restore register
Unlk A6 ; clear stack frame
Rtd #result-return-4 ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE Index2Entries(srcIndex: LONGINT; results:HANDLE):LONGINT;
;
; resize the handle, and return it filled with a list of INTEGERs. The first
; integer is the count, and the rest are the entries in the current port's
; palette that would match to the specified index.
Index2Entries PROC EXPORT
IEVars RECORD {A6Link},DECREMENT
result DS.B 0 ;Result: none
srcIndex DS.B 2 ;Input: entry in palette of current port
results DS.B 4 ;Input: any old handle
return DS.B 4
A6Link DS.B 4 ; old contents of A6
linkSize DS.B 0 ; linky number
ENDR
WITH IEVars
LINK A6,#linkSize
MOVEM.L D3-D7/A2,-(SP)
Move.L GrafGlobals(A5),A0 ; get the QuickDraw globals pointer
Move.L ThePort(A0),D0 ; point at the port
BEQ.S @goHome ; No port set?
SUBQ #4,SP
MOVE.L D0,-(SP)
_GetPalette ; Get the current palette
MOVE.L (SP)+,D0 ; Get something?
BEQ.S @goHome
MOVE.L D0,A0
MOVE.L (A0),A0
MOVE pmEntries(A0),D4 ; D4 = number of entries in palette
MOVE.L results(A6),D0 ; Get handle to return stuff in
BEQ.S @goHome ; A problem, to be sure.
MOVEA.L D0,A0
_HGetState
MOVE.B D0,D3 ; D3 = previous state of their handle
_HNoPurge
_HUnlock
MOVE D4,D0 ; D0 = number of entries in palette
ADD D0,D0 ; D0 = twice number of palette entries
ADDQ #2,D0
EXT.L D0 ; D0 = the biggest handle we'd need
_SetHandleSize ; Now, A0 is the right sized handle
_HLock
MOVE.L (A0),A2 ; A2-> where everything will go.
CLR.L D5 ; D5 = number of entries we've found
MOVE.L srcIndex(A6),D6 ; D6 = index we're looking for
BRA.S @scanEnd
@scanLoop SUBQ #4,SP ; Space for long result index
MOVE D4,-(SP)
_Entry2Index
CMP.L (SP)+,D6 ; Does this entry match our index?
BNE.S @scanEnd
ADDQ #1,D5 ; Found one more...
MOVE D4,(A2,D5*2) ; Put the entry into the list o' entries
@scanEnd DBRA D4,@scanLoop
MOVE.L results(A6),A0
MOVE.L D5,D0
ADD.L D0,D0
ADDQ.L #2,D0
_SetHandleSize
MOVE.B D3,D0
_HSetState
@goHome MOVEM.L (SP)+,D3-D6/A2
UNLK A6
RTD #result-return-4
;---------------------------------------------------
;
; PROCEDURE PmForeColor(srcEntry: INTEGER); INLINE $AA97;
;
PmForeColor PROC EXPORT
EXPORT PmBackColor
PCVars RECORD {A6Link},DECREMENT
result DS.B 0 ;Result: none
srcEntry DS.B 2 ;Input: entry in palette of current port
return DS.B 4
A6Link DS.B 4 ; old contents of A6
callType DS.B 2 ; Fore- or Back- call
linkSize DS.B 0 ; linky number
ENDR
WITH PCVars
;PmForeColor
MoveQ #1,D0 ; we're coming from PmForeColor
Bra.S PmSetColor ; share code
PmBackColor MoveQ #0,D0 ; we're coming from PmBackColor
PmSetColor Link A6,#linkSize ; build stack frame
Move D0,callType(A6) ; save the type of call
CLR.L -(SP) ; Room for result
MOVE srcEntry(A6),-(SP) ; Push the entry input
_Entry2Index ; Find a good index for it
MOVE.L (SP)+,D0 ; Get index (if any) into D0
TST QDErr ; Found one?
BNE.S GoHome ; No, skip it.
Move.L GrafGlobals(A5),A0 ; get the QuickDraw globals pointer
Move.L ThePort(A0),A0 ; point at the port
MOVE.L GrafVars(A0),A1 ; A1 = Grafvars handle
MOVE.L (A1),A1 ; A1->Grafvars
MOVE.L D0,-(SP) ; Push index for Index2Color <dvb9>
Tst callType(A6) ; foreground? AWC.PB377
Beq.S SetBackgrnd ; no => set background AWC.PB377
Move.L D0,FgColor(A0) ; jam the index
Move srcEntry(A6),PmFgIndex(A1) ; save the entry number
BSet #PmFgBit,PmFlags+1(A1) ; tell the world that we set the FgColor
PEA rgbFgColor(A0) ; Push address of color result o' Index2Color <dvb9>
Bra.S ToColor ; continue AWC.PB377
SetBackgrnd Move.L D0,BkColor(A0) ; jam the index AWC.PB377
Move srcEntry(A6),PmBkIndex(A1) ; save the entry number
BSet #PmBkBit,PmFlags+1(A1) ; tell the world that we set the BkColor
PEA rgbBkColor(A0) ; Push address of color result o' Index2Color <dvb9>
ToColor _Index2Color ; Give port rgb color from index result <dvb9>
GoHome Unlk A6 ; clear stack frame
Rtd #result-return-4 ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE AnimateEntry(dstWindow: WindowPtr; dstEntry: INTEGER; srcRGB: RGBColor); INLINE $AA99;
;
AnimateEntry PROC EXPORT
ParamSize equ 10 ; total bytes of params <AWC>
dstWindow equ ParamSize+8-4 ; target window <AWC>
dstEntry equ dstWindow-2 ; palette entry to animate <AWC>
srcRGB equ dstEntry-4 ; new color to use
SaveGDevice equ -4 ; room for saving theGDevice
Mc equ SaveGDevice-6 ; RGBColor
OldSeed equ Mc-4 ; old color table seed
VarSize equ OldSeed ; size of the variables
Link A6,#VarSize ; build stack frame
MoveM.L D3-D5/A2-A4,-(SP) ; save registers
Move.L PMgrHandle,A3 ; get the main handle
CmpA.L #PMgrNil,A3 ; are we initialized?
Beq GoHome ; no => punt AWC.PB377
Move.L dstWindow(A6),A0 ; get the target window
CmpA.L #Nil,A0 ; is it nil?
Beq GoHome ; yes => we're done AWC.PB377
Tst PortBits+Rowbytes(A0) ; is it a new port?
Bpl GoHome ; no => punt AWC.PB377
Move.L GrafVars(A0),A0 ; get the data handle
Move.L (A0),A0 ; dereference it
Move.L PmFgColor(A0),A2 ; get the palette handle (finally)
Move.L A2,D0 ; CmpA.L #Nil,A2; is there a palette? AWC.PB508
Bne.S FoundAPltt ; yes => use it AWC.PB508
Move.L AppPalette,A2 ; look for an AppPalette AWC.PB508
Move.L A2,D0 ; CmpA.L #Nil,A2; is there an AppPalette? AWC.PB508
Beq GoHome ; no => punt AWC.PB377
FoundAPltt Move.L (A2),A0 ; dereference the palette AWC.PB508
Move pmEntries(A0),D0 ; get the number of entries
MoveQ #0,D1 ; clear high word
Move dstEntry(A6),D1 ; get the index
Cmp D0,D1 ; is the index in range?
Bhs GoHome ; no => we're done AWC.PB377
Lsl #4,D1 ; multiply by ciSize
Lea pmInfo(A0,D1.L),A2 ; point A2 at the entry
; BTst #ExplicitBit,ciUsage+1(A2) ; is it explicit? <dvb4>
; Bne GoHome ; yes => by definition not animating <dvb4>
BTst #AnimatedBit,ciUsage+1(A2) ; is it animating?
Beq GoHome ; no => quit
; Copy the colors to the palette before we check to see if we have links or not so that it
; will get copied even if we have no 'clut' devices
Move.L srcRGB(A6),A0 ; get pointer to his RGB AWC.PB500
Move.L red(A0),D0 ; copy red and green AWC.PB500
Move.L D0,mc+red(A6) ; save red and green on the stack AWC.PB500
ROR.L #8,D0 ; Get at upper bytes of colors <dvb6>
MOVE.b d0,ciRGB+green(A2) ; Only store high byte (lo is SetColor <dvb11>
SWAP D0 ; get at red byte <dvb6>
MOVE.B D0,ciRGB+red(A2) ; Only store high byte (lo is SetColor <dvb11>
Move blue(A0),D0 ; copy blue AWC.PB500
Move D0,mc+blue(A6) ; save blue on the stack AWC.PB500
ROR #8,D0 ; get at significant byte of blue <dvb6>
MOVE.B D0,ciRGB+blue(A2) ; Only store high byte (lo is SetColor <dvb11>
Move ciPrivate(A2),D3 ; get the ForeLink field
BfExtu D3{16:3},D1 ; get the key bits
Cmp #4,D1 ; were they 100?
Bne GoHome ; no => not a valid ForeLink; go home
; Now, finally, we have something to do. Let's follow those links and see where they take us
Move.L A3,A0 ; copy PMgrHandle
_HLock ; lock it down
Move.L theGDevice,SaveGDevice(A6) ; save it
; Register usage:
;
; D0 : holds ForeLink temporarily
; D3 : holds device number
; D4 : holds index number
; D5 : watchdog loop counter
;
; A2 : base address of LinkTabs
; A3 : PMgrHandle (locked)
; A4 : base address of DevHandles
Move.L (A3),A2 ; dereference PMgrHandle
Move nDevs(A2),D5 ; maximum number of devices (watchdog counter)
Lea DevHandles(A2),A4 ; point A4 at the device list
AddA.L #LinkTabs,A2 ; point A2 at start of LinkTabs
Move D3,D0 ; copy ForeLink into D0
Bra.S DevEnd ; jump into the loop
DevLoop BfExtU D0{19:5},D3 ; grab device number (0..31)
BfExtU D0{24:8},D4 ; grab index number (0..255)
Move.L DevHandle(A4,D3.W*8),A0 ; get the device handle
Move.L A0,theGDevice ; now we're on that device
Move.L (A0),A0 ; dereference it
Clr gdId(A0) ; no client id's, please
Move.L gdPMap(A0),A0 ; get handle to pixmap
Move.L (A0),A0 ; dereference pixmap
Move.L pmTable(A0),A0 ; get handle to CTab
Move.L (A0),A0 ; dereference CTab
Move ctSize(A0),D0 ; grab number of entries - 1
Cmp D4,D0 ; compare our index to the max index
Ble.S NextDevice ; out of range => look at next device AWC.PB480
Move.L ctSeed(A0),OldSeed(A6) ; save the seed so we can restore it
Move.L mc+red(A6),ctTable+RGB+red(A0,D4.W*8)
Move mc+blue(A6),ctTable+RGB+blue(A0,D4.W*8)
; Now perform a sequential _SetEntries using the device's color table as the source
MOVE D4,-(SP) ; push D4 = Index for SetEntries
CLR -(SP) ; push number of entries-1 = 1
Pea ctTable(A0,D4*8) ; push address of the first ColorSpec
_SetEntries ; do it
Move.L theGDevice,A0 ; get the device again
Move.L (A0),A0 ; dereference it
Move.L gdPMap(A0),A0 ; get handle to pixmap
Move.L (A0),A0 ; dereference pixmap
Move.L pmTable(A0),A0 ; get handle to CTab
Move.L (A0),A0 ; dereference CTab
Move.L OldSeed(A6),ctSeed(A0) ; we didn't really want it to change
NextDevice Lsl #8,D3 ; calculate offset to link table/4
Add D4,D3 ; offset to entry/4
Move ForeLink(A2,D3.L*4),D0 ; get next link; is the top bit set? AWC.PB500
DevEnd DBpl D5,DevLoop ; keep going until D0 is positive or D5 runs out
Move.L SaveGDevice(A6),theGDevice ; restore theGDevice
Move.L A3,A0 ; copy PMgrHandle
_HUnlock ; unlock it
GoHome MoveQ #0,D0 ; no error AWC.PB377
MoveM.L (SP)+,D3-D5/A2-A4 ; restore registers
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE AnimatePalette(dstWindow:WindowPtr; srcCTab: CTabHandle; srcIndex,
; dstEntry,dstLength: INTEGER; INLINE $AA9A;
;
AnimatePalette PROC EXPORT
ParamSize equ 14 ; total bytes of params <AWC>
dstWindow equ ParamSize+8-4 ; window to animate <AWC>
srcCTab equ dstWindow-4 ; new source colors
srcIndex equ srcCTab-2 ; first source entry to use
dstEntry equ srcIndex-2 ; first destination entry to set
dstLength equ dstEntry-2 ; how many to set
SaveGDevice equ -4 ; room for saving theGDevice
SaveSeed equ SaveGDevice-4 ; old color table seed
NumDev equ SaveSeed-2 ; copy of nDevs
DevCTabH equ NumDev-DevLimit*4 ; enough room for a CTabHandle per device
VarSize equ DevCTabH ; size of the variables
Link A6,#VarSize ; build stack frame
MoveM.L D3-D6/A2-A4,-(SP) ; save registers
Move.L PMgrHandle,A4 ; get the main handle
CmpA.L #PMgrNil,A4 ; are we initialized?
Beq GoHome ; no => punt AWC.PB377
Move.L dstWindow(A6),A0 ; get the target window <AWC>
CmpA.L #Nil,A0 ; is it nil? <AWC>
Beq GoHome ; yes => we're done AWC.PB377
Tst PortBits+Rowbytes(A0) ; is it a new port?
Bpl GoHome ; no => punt AWC.PB377
Move.L GrafVars(A0),A0 ; get the data handle
Move.L (A0),A0 ; dereference it
Move.L PmFgColor(A0),A2 ; get the palette handle (finally)
Move.L A2,D0 ; CmpA.L #Nil,A2; is there a palette? AWC.PB508
Bne.S FoundAPltt ; yes => use it AWC.PB508
Move.L AppPalette,A2 ; look for an AppPalette AWC.PB508
Move.L A2,D0 ; CmpA.L #Nil,A2; is there an AppPalette? AWC.PB508
Beq GoHome ; no => punt AWC.PB508
FoundAPltt Move.L srcCTab(A6),A3 ; get source color table AWC.PB508
Move.L A3,D0 ; CmpA.L #Nil,A3; is it nil? AWC.PB508
Beq GoHome ; yes => again punt AWC.PB377
Move.L (A2),A2 ; dereference the palette
Move pmEntries(A2),D0 ; get the number of entries; are there any?
Beq GoHome ; no => still punt AWC.PB377
MoveQ #0,D3 ; clear high word (so we can Lsl.L later)
Move dstEntry(A6),D3 ; get the starting index
Cmp D0,D3 ; is the start after the end?
Bhs GoHome ; yes => keep punting
Move.L (A3),A3 ; dereference the color table
Move srcIndex(A6),D4 ; get the starting index
Cmp ctSize(A3),D4 ; is the starting index within range?
Bhi GoHome ; no => once more, punt
; We have something worth copying! Now we can determine the length of the copy and
; place it in D5.
Sub D3,D0 ; calculate maximum length of a palette copy
Move D0,D5 ; save it in D5
Move ctSize(A3),D0 ; fetch the length of the color table
AddQ #1,D0 ; add 1 to make it 1-based
Sub D4,D0 ; calculate maximum length of a CTab copy
Cmp D0,D5 ; is D5 too big?
Bls.S NotTooBig ; no => don't replace it
Move D0,D5 ; copy smaller value to D5
NotTooBig Cmp dstLength(A6),D5 ; is D5 bigger than the request?
Bls.S StillOkay ; no => leave it alone
Move dstLength(A6),D5 ; copy smaller value to D5
StillOkay Move.L (A4),A1 ; dereference the palette manager handle
Move nDevs(A1),D0 ; put number of devices into D0
Move D0,NumDev(A6) ; remember number of devices
Lea DevHandles(A1),A4 ; point A4 at the clut device list AWC
Lea DevCTabH(A6),A0 ; point A0 at our temporary table AWC
Bra.S ClearEnd ; jump into loop
ClearLoop Clr.L (A0)+ ; clear room for a handle AWC
ClearEnd DBra D0,ClearLoop ; continue for nDevs devices AWC
AddA.L #LinkTabs,A1 ; bump A1 to the link tables
Lsl.L #4,D3 ; multiply D3 by ciSize
Lea pmInfo(A2,D3.L),A2 ; bump A2 to first ColorInfo
Lea ctTable(A3,D4.W*8),A3 ; bump A3 to first ColorSpec
Bra EntryEnd ; jump into loop
EntryLoop BTst #AnimatedBit,ciUsage+1(A2) ; is it animating?
Beq NextEntry ; no => continue
MOVE.b RGB+red(A3),ciRGB+red(A2) ; red hi into our hibyte <dvb11>
MOVE.b RGB+green(A3),ciRGB+green(A2) ; green hi into our hibyte <dvb11>
MOVE.b RGB+blue(A3),ciRGB+blue(A2) ; blue hi into our hibyte <dvb11>
Move ciPrivate(A2),D0 ; get the ForeLink field
BfExtu D0{16:3},D1 ; get the key bits
Cmp #4,D1 ; were they 100?
Bne.S NextEntry ; no => not a valid ForeLink; go home
Move NumDev(A6),D6 ; get maximum number of devices to examine
SubQ #1,D6 ; decrement by 1 so we may fall through
; We fall through because the usual trick of branching to the end won't work when the
; end is a DBpl, not a DBf (DBra).
DevLoop BfExtU D0{19:5},D3 ; grab device number (0..31)
BfExtU D0{24:8},D4 ; grab index number (0..255)
Lea DevCTabH(A6),A0 ; point A0 at temporary table
Move.L (A0,D3.W*4),A0 ; get CTabHandle
CmpA.L #Nil,A0 ; have we seen this device yet?
Bne.S SeenDevice ; yes => skip setup
Move.L DevHandle(A4,D3.W*8),A0 ; get the device handle
Move.L (A0),A0 ; dereference it
Clr gdId(A0) ; no client id's, please
Move.L gdPMap(A0),A0 ; get handle to pixmap
Move.L (A0),A0 ; dereference pixmap
Move.L pmTable(A0),D0 ; get handle to CTab
Lea DevCTabH(A6),A0 ; point A0 at temporary table
Move.L D0,(A0,D3.W*4) ; save it for later
Move.L D0,A0 ; copy CTabHandle back into A0 AWC PB223
SeenDevice Move.L (A0),A0 ; dereference CTab
Move ctSize(A0),D0 ; grab number of entries - 1
Cmp D4,D0 ; compare our index to the max index
Ble.S NextDevice ; out of range => look at next device AWC.PB480
Move.W ciRGB+red(A2),ctTable+RGB+red(A0,D4.W*8) ;<dvb11>
Move.W ciRGB+green(A2),ctTable+RGB+green(A0,D4.W*8) ;<dvb11>
Move.W ciRGB+blue(A2),ctTable+RGB+blue(A0,D4.W*8) ;<dvb11>
NextDevice Lsl #8,D3 ; calculate offset to link table/4
Add D4,D3 ; offset to entry/4
Move ForeLink(A1,D3.L*4),D0 ; get next link; is the top bit set?
DevEnd DBpl D6,DevLoop ; keep going until D0 is positive or D5 runs out
NextEntry AddA.L #ciSize,A2 ; bump A2 to next ColorInfo
AddA.L #ColorSpecSize,A3 ; bump A3 to next ColorSpec
EntryEnd DBra D5,EntryLoop ; continue for all animating entries
Move.L theGDevice,SaveGDevice(A6) ; save the old GDevice
Move NumDev(A6),D6 ; get number of devices to examine
Lea DevCTabH(A6),A2 ; point A2 at our temporary table
Bra.S SetEnd ; jump into loop
SetLoop Move.L (A2)+,A3 ; get next CTabHandle
CmpA.L #Nil,A3 ; did we initialize it?
Beq.S NextSet ; no => continue
Move.L DevHandle(A4),theGDevice ; put us on that device
Move.L (A3),A0 ; dereference it
Move.L ctSeed(A0),SaveSeed(A6) ; save the current seed
Clr -(SP) ; push starting count of 0 for SetEntries
Move ctSize(A0),-(SP) ; push number of entries-1
Pea ctTable(A0) ; push address of the first ColorSpec
_SetEntries ; do it
Move.L (A3),A0 ; dereference CTab again
Move.L SaveSeed(A6),ctSeed(A0) ; put the old seed back into place
NextSet AddQ.L #DevInfoSz,A4 ; bump A4 to the next device
SetEnd DBra D6,SetLoop ; loop for all devices
Move.L SaveGDevice(A6),theGDevice ; restore the old GDevice
GoHome MoveQ #0,D0 ; clear error condition AWC.PB377
MoveM.L (SP)+,D3-D6/A2-A4 ; rsstore registers
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE GetEntryColor(srcPalette: PaletteHandle; srcEntry: INTEGER; VAR dstRGB: RGBColor);
; INLINE $AA9B;
;
GetEntryColor PROC EXPORT
ParamSize equ 10 ; total bytes of params
srcPalette equ ParamSize+8-4 ; source Palette handle
srcEntry equ srcPalette-2 ; entry to get
dstRGB equ srcEntry-4 ; where to put color
VarSize equ 0
Link A6,#VarSize ; build stack frame
Move.L srcPalette(A6),A0 ; get palette
CmpA.L #Nil,A0 ; is it nil?
Beq.S GoHome ; yes => punt AWC.PB377
Move.L (A0),A0 ; dereference it
Move pmEntries(A0),D0 ; get the number of entries
MoveQ #0,D1 ; clear high word
Move srcEntry(A6),D1 ; get the index
Cmp D0,D1 ; is the index in range?
Bhs.S GoHome ; no => we're done AWC.PB377
Lsl.L #4,D1 ; multiply by number of records
Lea pmInfo(A0,D1.L),A0 ; point A0 at the correct ColorInfo
Move.L dstRGB(A6),A1 ; get the destination
Move.L ciRGB+red(A0),red(A1) ; copy red and green
Move ciRGB+blue(A0),blue(A1) ; copy blue
GoHome MoveQ #0,D0 ; clear error condition
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE ScatterDevices(SetEm:Boolean); Local; <dvb3>
;
; Here is the long awaited ScatterDevices, which gives animated entries back to
; the world in a socially acceptable manner. The default clut for the device
; is used to fill in those entries of the device's clut marked with bit 4,
; the ctScatterBit. Then, the bits for those devices with new colors is set in
; the updateDevs bitmask of PMgrHandle.
; We restore all registers.
ScatterDevices PROC EXPORT
SDVars RECORD {A6Link},DECREMENT
result DS.B 0 ;Result: none
SetEm DS.B 2 ;Input: boolean, to set the entries really
return DS.B 4
A6Link DS.B 4 ;old contents of A6
linkSize DS.B 0 ;linky number
ENDR
WITH SDVars
LINK A6,#linkSize
MOVEM.L A0/A2-A4/D1-D5,-(SP) ; Save some regs
MOVE.L PMgrHandle,A0
MOVE.L (A0),A0 ; A0 -> PMgr data
MOVE.L scatterDevs(A0),D4 ; D4 = bitmask of devices needing scattering
BEQ GoHome ; What? No scattering?
CLR.L scatterDevs(A0) ; We'll scatter these
OR.L D4,updateDevs(A0) ; So mark them for updating
MOVE nDevs(A0),D3 ; D3 = number of devices to check
SUBQ #1,D3 ; less one (we've got _one_ device, right?)
LEA DevHandles(A0),A2 ; A2 -> list of devices
ScatterLoop BTST D3,D4 ; Do this device?
BEQ ScatterEnd ; No=> skip some stuff
SUBQ #4,SP ; space for result
MOVE.L DevHandle(A2,D3*8),A3 ; A3 = device handle
MOVE.L A3,-(SP) ; push device handle
JSR GetClut ; get us a handle
MOVE.L (SP)+,A4 ; Keep copy on stack
MOVE.L (A4),A4 ; A4-> system color table for that depth
MOVE.L ctSeed(A4),D2 ; D2 = system seed for that depth
LEA ctTable+rgb(A4),A4 ; A4-> rgb of first color entry
MOVE.L (A3),A3 ; A3->gDevice
MOVE.L gdPMap(A3),A3 ; A3 = pixmaphandle
MOVE.L (A3),A3 ; A3->pixmap
MOVE.L pmTable(A3),A3 ; A3 = our color table H
MOVE.L (A3),A3 ; A3-> our color table
MOVE ctSize(A3),D1
LEA ctTable(A3),A0 ; A0->value of colorspec 0
CLR D5 ; No elements scattered
EntryLoop BTST #ctMatchBit,value(A0) ; Is this entry looked at?
BEQ.S CheckScat ; No=>check next one
ADDQ #1,D5 ; Count number of unreserved entries
CheckScat BTST #ctScatterBit,value(A0) ; Is the scatterbit on?
BEQ.S EntryEnd ; No=>check next one
CLR value(A0) ; Mark it as unreserved, scattered, etc.
MOVE.L red(A4),rgb+red(A0) ; Move red and green component from system clut
MOVE blue(A4),rgb+blue(A0) ; Move blue from system clut
EntryEnd ADDQ #8,A0 ; Bump A0 to next color entry
ADDQ #8,A4 ; Bump A4 to next color entry
DBRA D1,EntryLoop
MOVE.L DevHandle(A2,D3*8),A4 ; A4 = device handle
CMP ctSize(A3),D5 ; Is every entry in place as in default?
BLE.S NewSeed ; No=>give cTab a new seed
MOVE.L D2,ctSeed(A3) ; Yes=>we get system seed here
MOVE.L (A4),A0 ; A0->gDevice
MOVE.L gdITable(A0),A0 ; A0 = Inverse table handle
MOVE.L (A0),A0 ; A0-> ITable
CLR.L (A0) ; Change ITab seed instead!
BRA.S MaybeSet
NewSeed SUBQ #4,SP ; Space for result
_GetCTSeed ; Get us a new seed
MOVE.L (SP)+,ctSeed(A3) ; And give it a new seed.
MaybeSet TST SetEm(A6) ; So, do we actually update the device?
BEQ.S ScatterEnd ; No=>do next device
MOVE.L A4,A0 ; Put gDev handle in A0
JSR DevSetEntries ; And put entries into HW clut, w/o changing seed.
ScatterEnd DBRA D3,ScatterLoop
GoHome MOVEM.L (SP)+,A0/A2-A4/D1-D5
UNLK A6
RTD #result-return-4
;---------------------------------------------------
;
; PROCEDURE SetDev; LOCAL;
;
; Renders or allocates myPalette as appropriate for the given device. If myPalette
; is polite it accumulates reference counts. If it is intolerant it assigns indexes
; according to closest match and makes these colors available in the color table. If
; it is adamant (animated) it chooses indexes according to lowest reference counts
; and reserves the entries on the device (setting the reserve bit).
;
; This function uses the stack frame built upon A6 and builds its own stack frame on A4.
PROC
EXPORT SetDev
OldPort equ -8 ; a place to stuff the port while we InvalRect
SysUpdates equ OldPort-2 ; flag that tells whether the system wants updates
OldUpdates equ SysUpdates-2 ; flag => 1 if Old Quickdraw colors got changed AWC
VarSize equ OldUpdates ; number of bytes of variables AWC PB223
DepthBits DC.B 8,9,10,11,0,0,12,13 ; Inhibit bits for different depths/grays
; (depth) 2 2 4 4 8 8
; (color?) n y n y n y
SetDev
Link A4,#VarSize ; build stack frame
MoveM.L D3-D5/A2-A3,-(SP) ; save registers <AWC>
; Grab the device handle and shove it into theGDevice
Move CurDevice(A6),D3 ; get device offset
Move.L PDevPtr(A6),A0 ; get pointer to internal list of devices
Move.L (A0,D3.W*8),A0 ; get the device handle
Move.L A0,theGDevice ; set theGDevice
; Removed code that calculated device info - see CalcDevs below AWC PB223
Move.L (A0),A0 ; dereference it
TST gdType(A0) ; is it CLUT type (zero)? dvb1
BNE GoHome ; No => do nothing
MOVE $14(A0),D0
AND #$8010,D0
BEQ GoHome ; No=>go home
Move.L gdPMap(A0),A0 ; get handle to pixmap
Move.L (A0),A0 ; dereference pixmap
Move.L pmTable(A0),A0 ; get handle to CTab
Move.L A0,DevCTab(A6) ; save color table handle, too
Move.L (A0),A0 ; dereference CTab
Move ctSize(A0),D0 ; grab number of entries - 1
Move D0,BlackIndex(A6) ; save it
AddQ #1,D0 ; bump it to number of entries
Move D0,DevIndexes(A6) ; save the number of indexes, too
; Compare the palette's seed for this device to the ctSeed belonging to the
; device. If they match, no environment or palette change has occurred. The routines
; which modify palettes make sure that the appropriate seed fields get changed. If
; the user modifies the palette herself, she must take responsibility for changing
; the seeds accordingly.
Move.L ctSeed(A0),D0 ; read the current device seed
Move.L PalettePtr(A6),A0 ; get the Palette pointer
BTst #DirtyBit,pmPrivate(A0) ; does it need an update anyway?
Bne.S DirtyBird ; yes => activate it anyway
Move.L pmSeeds(A0),A0 ; get the handle to the seeds
Move.L (A0),A0 ; dereference it
Cmp.L (A0,D3.W*4),D0 ; does the Palette's seed match the device's?
Beq GoHome ; yes => skip this whole mess
; Set up some useful pointers
DirtyBird Move.L PDevPtr(A6),A0 ; get pointer to internal list of devices
Lea (A0,D3.W*8),A0 ; point A0 at the device entry
Move.L PMgrPtr(A6),A0 ; copy base pointer
AddA.L #LinkTabs,A0 ; add offset to first link table
Move D3,D0 ; get the device number (0..31)
Lsl #8,D0 ; multiply by link table size (max 31*1024)
Lea (A0,D0.W*4),A0 ; point A0 at link table
Move.L A0,DevLinks(A6) ; save pointer to device links table
; Set Updates to 0 so we'll know if a SetEntries is necessary. Make a copy
; of ciUsage flags in ciFlags.
Clr Updates(A6) ; clear number of updates to CTab we've done
MOVE.L TheGDevice,A0 ; A0 = Current device handle
MOVE.L (A0),A0 ; A0->Current device
MOVE gdFlags(A0),D3 ; D3 = gDev's flags
AND #1,D3 ; D3 = 0:b/w or 1:color
MOVE.L gdPMap(A0),A0 ; A0 = current device pixmap
MOVE.L (A0),A0 ; A0->current device pixmap
ADD pmPixelSize(A0),D3 ; D3 = pixeldepth, +1 if color
LEA depthBits-2,A0
MOVE.B (A0,D3.W),D3 ; D3 = bit of ciUsage to test for inhibit on this gDev
Move myEntries(A6),D0 ; get myPalette^^.pmEntries
Move.L PalettePtr(A6),A0 ; get the pointer to the palette
Lea pmInfo(A0),A0 ; bump it to the first ColorInfo
Bra.S InitEnd ; jump into the fray
InitLoop Move ciUsage(A0),D1 ; D1 = usage flags, plus global HandledBit
BTST D3,D1 ; Inhibit on this device?
BEQ.S @noInhib
BSET #handledBit,D1 ; Yes, just mark as "handled"
@noInhib MOVE D1,ciFlags(A0) ; copy ciUsage to ciFlags
AddA.L #ciSize,A0 ; bump A0 to the next ColorInfo
InitEnd DBra D0,InitLoop ; loop for pmEntries
JSR AnalyzeDev ; Make list of device indices to grab
Jsr PMAllocate ; Get animated entries
Jsr Correlate ; Get tolerant entries
; Now we are ready to set some colors (for real, man!). We have been changing colors
; in the device's color table all along. Now we just need to promulgate them through
; to the device with a sequential SetEntries call, but only if Updates is greater than
; zero. In order to make the call we have to unprotect each color and set it's client
; id to "none". Then we do the SetEntries call, after which we restore the protection
; and client id (255) of all colors. Next we copy the seed from the device color table
; to the palette so we'll know we've been here. Finally we generate update events for
; all windows of palettes which have been rendered on this device, including of course
; the current palette.
CheckUpdate TST Updates(A6)
BEQ.S FixSeeds
JSR MarkDevUBit
FixSeeds Move.L DevCTab(A6),A0 ; get color table
Move.L (A0),A0 ; dereference it
Move.L ctSeed(A0),D0 ; read the current device seed
Move.L PalettePtr(A6),A0 ; get the Palette pointer
Move.L pmSeeds(A0),A1 ; get the handle to the seeds
Move.L (A1),A1 ; dereference it
Move CurDevice(A6),D3 ; get device number back
Move.L D0,(A1,D3.W*4) ; update the Palette's seed
GoHome MoveQ #0,D0 ; clear error condition AWC.PB377
MoveM.L (SP)+,D3-D5/A2-A3 ; restore registers <AWC>
Unlk A4 ; clear stack frame
Rts ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE SetEntryColor(dstPalette: PaletteHandle; dstEntry: INTEGER; srcRGB: RGBColor);
; INLINE $AA9C;
;
SetEntryColor PROC EXPORT
ParamSize equ 10 ; total bytes of params
dstPalette equ ParamSize+8-4 ; source Palette handle
dstEntry equ dstPalette-2 ; entry to set
srcRGB equ dstEntry-4 ; new color
VarSize equ 0
Link A6,#VarSize ; build stack frame
Move.L dstPalette(A6),A0 ; get palette
CmpA.L #Nil,A0 ; is it nil?
Beq.S GoHome ; yes => punt AWC.PB377
Move.L (A0),A0 ; dereference it
Move pmEntries(A0),D0 ; get the number of entries
MoveQ #0,D1 ; clear high word
Move dstEntry(A6),D1 ; get the index
Cmp D0,D1 ; is the index in range?
Bhs.S GoHome ; no => we're done AWC.PB377
Lsl.L #4,D1 ; multiply by number of records
Lea pmInfo(A0,D1.L),A0 ; point A0 at the correct ColorInfo
Move.L srcRGB(A6),A1 ; A1->source
Move.L red(A1),ciRGB+red(A0) ; copy red and green,
Move blue(A1),ciRGB+blue(A0) ; copy blue
BTST #animatedBit,ciUsage+1(A0) ; Is it animated? <dvb13>
BEQ.S @notAni ; No=> don't replicate bytes <dvb13>
LEA ciRGB(A0),A0 ; (A nop, I think)
MOVE.B (A0)+,(A0)+ ; we replicate the high bytes
MOVE.B (A0)+,(A0)+ ; of each component into the low bytes
MOVE.B (A0)+,(A0)+
@notAni Move.L dstPalette(A6),-(SP) ; push the palette handle AWC.PB508
Bsr DirtySeeds ; clear the device seeds AWC.PB508
GoHome MoveQ #0,D0 ; clear error condition AWC.PB377
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE GetEntryUsage(srcPalette: PaletteHandle; srcEntry: INTEGER; VAR dstUsage,
; dstTolerance: INTEGER); INLINE $AA9D;
;
GetEntryUsage PROC EXPORT
ParamSize equ 14 ; total bytes of params
srcPalette equ ParamSize+8-4 ; source Palette handle
srcEntry equ srcPalette-2 ; entry number
dstUsage equ srcEntry-4 ; where to put usage
dstTolerance equ dstUsage-4 ; where to put tolerance
VarSize equ 0
Link A6,#VarSize ; build stack frame
Move.L srcPalette(A6),A0 ; get palette
CmpA.L #Nil,A0 ; is it nil?
Beq.S GoHome ; yes => punt AWC.PB377
Move.L (A0),A0 ; dereference it
Move pmEntries(A0),D0 ; get the number of entries
MoveQ #0,D1 ; clear high word
Move srcEntry(A6),D1 ; get the index
Cmp D0,D1 ; is the index in range?
Bhs.S GoHome ; no => we're done AWC.PB377
Lsl.L #4,D1 ; multiply by number of records
Lea pmInfo(A0,D1.L),A0 ; point A0 at the correct ColorInfo
Move.L dstUsage(A6),A1 ; get the destination
Move ciUsage(A0),(A1) ; copy usage
Move.L dstTolerance(A6),A1 ; get the second destination
Move ciTolerance(A0),(A1) ; copy tolerance
GoHome MoveQ #0,D0 ; clear error condition AWC.PB377
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE SetEntryUsage(dstPalette: PaletteHandle; dstEntry,srcUsage,srcTolerance: INTEGER);
; INLINE $AA9E;
;
SetEntryUsage PROC EXPORT
IMPORT ClearStrand
ParamSize equ 10 ; total bytes of params
dstPalette equ ParamSize+8-4 ; source Palette handle
dstEntry equ dstPalette-2 ; entry number
srcUsage equ dstEntry-2 ; new usage
srcTolerance equ srcUsage-2 ; new tolerance
VarSize equ 0
Link A6,#VarSize ; build stack frame
MOVEM.L A2-A4/D3-D4,-(SP) ; save regs <dvb3>
Move.L dstPalette(A6),A0 ; get palette
CmpA.L #Nil,A0 ; is it nil?
Beq.S GoHome ; yes => punt AWC.PB377
Move.L (A0),A0 ; dereference it
Move pmEntries(A0),D0 ; get the number of entries
MoveQ #0,D1 ; clear high word
Move dstEntry(A6),D1 ; get the index
Cmp D0,D1 ; is the index in range?
Bhs.S GoHome ; no => we're done AWC.PB377
Lsl.L #4,D1 ; multiply by number of records
Lea pmInfo(A0,D1.L),A2 ; point A2 at the correct ColorInfo
MOVE ciUsage(A2),D0 ; D0 = old usage <dvb3>
BTST #AnimatedBit,D0 ; Was it animated before? <dvb3>
BEQ.S NoScat ; If not, we've nothing to release <dvb3>
MOVE srcUsage(A6),D3
EOR D3,D0 ; And, which bits changed <dvb3>
AND #$3F0C,D0 ; Animated, explicit, OR inhibits? <dvb4>
BEQ.S noScat ; None? No change to fix <dvb4>
MOVE ciPrivate(A2),D3 ; Yes, were any indexes actually reserved? <dvb3>
BPL.S NoScat ; No => still no entries to release <dvb3>
MOVE.L PMgrHandle,A0 ; A0 = pmgr handle <dvb3>
MOVE.L (A0),A0 ; A0 ->pmgr data <dvb3>
LEA LinkTabs(A0),A3 ; A3 -> LinkTabs <dvb3>
LEA DevHandles(A0),A4 ; A4 -> Device handles <dvb3>
CLR.L D4 ; No devices affected... yet <dvb3>
JSR ClearStrand ; clear linktab/ctTable entries <dvb3>
MOVE.L PMgrHandle,A0 ; A0 = pmgr handle <dvb3>
MOVE.L (A0),A0 ; A0 ->pmgr data <dvb3>
OR.L D4,scatterDevs(A0) ; Mark some devices for scattering <dvb3>
CLR ciPrivate(A2) ; We no longer own those indices. <dvb3>
NoScat MOVE srcUsage(A6),D0 ; Get new usage in D0 <dvb14>
BTST #AnimatedBit,D0 ; Will it be now animated? (rgrdlss prior state) <dvb14>
BEQ.S @NoDup ; No => don't dupe high/low bytes <dvb14>
LEA ciRGB(A2),A0 ; A0->rgb color <dvb14>
MOVE.B (A0)+,(A0)+ ; Dupe red into low byte <dvb14>
MOVE.B (A0)+,(A0)+ ; Dupe green into low byte <dvb14>
MOVE.B (A0)+,(A0)+ ; Dupe blue into low byte <dvb14>
@NoDup Move D0,ciUsage(A2) ; copy usage
Move srcTolerance(A6),ciTolerance(A2) ; copy tolerance
Move.L dstPalette(A6),-(SP) ; push the palette handle AWC.PB508
Bsr DirtySeeds ; clear the device seeds AWC.PB508
GoHome MoveQ #0,D0 ; clear error condition AWC.PB377
MOVEM.L (SP)+,A2-A4/D3-D4 ; restore regs <dvb3>
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE CTab2Palette(srcCTab: CTabHandle; dstPalette: PaletteHandle; myUsage,
; myTolerance: INTEGER); INLINE $AA9F;
;
CTab2Palette PROC EXPORT
ParamSize equ 12 ; total bytes of params
srcCTab equ ParamSize+8-4 ; source ColorTable handle
dstPalette equ srcCTab-4 ; destination Palette handle
srcUsage equ dstPalette-2 ; default usage value
srcTolerance equ srcUsage-2 ; default usage tolerance
VarSize equ 0
Link A6,#VarSize ; build stack frame
MoveM.L D3/A2-A3,-(SP) ; save registers
Move.L dstPalette(A6),A2 ; get palette
CmpA.L #Nil,A2 ; is it nil?
Beq GoHome ; can't deal with nil here either AWC.PB377
Move.L dstPalette(A6),-(SP) ; push Palette
Jsr ClearPalette ; clear animating entries and seed handle
Bne.S GoHome ; if not zero it was a bad palette AWC.PB457
Move.L srcCTab(A6),A3 ; get color table
CmpA #Nil,A3 ; is it nil?
Beq.S GoHome ; can't deal with a nil handle AWC.PB377
Move.L (A3),A1 ; dereference it
MoveQ #0,D3 ; clear high word of D3
Move ctSize(A1),D3 ; get size-1 of CTab
AddQ #1,D3 ; D3 is number of entries in palette
Move.L A2,A0 ; copy myPalette handle
Move.L D3,D0 ; copy size
AddQ #1,D0 ; include palette header
Asl #4,D0 ; multiply by 16 bytes per entry | header
_SetHandleSize ; do it
Bne.S GoHome ; and quit if we couldn't do it AWC.PB377
Move.L A2,-(SP) ; push the palette handle AWC.PB508
Bsr DirtySeeds ; clear the device seeds AWC.PB508
Move.L (A2),A0 ; dereference our handle
Move D3,pmEntries(A0) ; copy size
AddA.L #pmInfo,A0 ; bump us to the first ColorInfo
Move.L (A3),A1 ; dereference source handle again
AddQ.L #ctTable,A1 ; bump A1 to the first ColorSpec
Move srcUsage(A6),D1 ; grab myUsage from parameters
Swap D1 ; put it in high word
Move srcTolerance(A6),D1 ; grab myTolerance into low word
Bra.S CopyEnd ; jump into DBra loop
CopyLoop Move.L RGB+red(A1),ciRGB+red(A0) ; copy red and green <dvb11>
Move RGB+blue(A1),ciRGB+blue(A0) ; copy blue
BTST #animatedBit+16,D1 ; animated entry? <dvb13>
BEQ.S @notAni ; No=>don't mangle hi/lo bytes <dvb13>
MOVE.B RGB+red(A1),ciRGB+red+1(A0) ; copy red into lo byte
MOVE.B RGB+green(A1),ciRGB+green+1(A0) ; copy green into lo byte <dvb11>
MOVE.B RGB+blue(A1),ciRGB+blue+1(A0) ; copy blue into lo byte <dvb11>
@notAni Move.L D1,ciUsage(A0) ; copy myUsage and myTolerance
Clr ciFlags(A0) ; clear private flags
Clr ciPrivate(A0) ; clear private links
AddA.L #ciSize,A0 ; bump A0 to next ColorInfo
AddQ.L #ColorSpecSize,A1 ; bump A1 to next ColorSpec
CopyEnd DBra D3,CopyLoop ; decrement and branch until copy is done
GoHome MoveQ #0,D0 ; clear error AWC.PB377
MoveM.L (SP)+,D3/A2-A3 ; restore registers
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE Palette2CTab(srcPalette: PaletteHandle; dstCTab: CTabHandle); INLINE $AAA0;
;
Palette2CTab PROC EXPORT
ParamSize equ 8 ; total bytes of params
srcPalette equ ParamSize+8-4 ; source Palette handle
dstCTab equ srcPalette-4 ; destination CTabHandle
VarSize equ 0
Link A6,#VarSize ; build stack frame
MoveM.L D3/A2-A3,-(SP) ; save registers
; first grab MyPalette and myCTab and compare them to nil
Move.L srcPalette(A6),A2 ; get source into A2
CmpA #Nil,A2 ; is it nil?
Beq.S GoHome ; punt if no palette AWC.PB377
Move.L dstCTab(A6),A3 ; get destination into A3
CmpA #Nil,A3 ; is it nil?
Beq.S GoHome ; punt if no ctab AWC.PB377
; leave size in D0; dereference both handles and capture pmEntries
Move.L (A2),A0 ; dereference myPalette
MoveQ #0,D3 ; clear high word
Move pmEntries(A0),D3 ; get number of palette entries
Move.L D3,D0 ; copy length
AddQ.L #1,D0 ; add 1 for the header
Lsl.L #3,D0 ; multiply by size of ColorSpec
Move.L A3,A0 ; put handle in A0
_SetHandleSize ; resize it
Bne.S GoHome ; <> 0 => couldn't handle it AWC.PB377
Move.L (A2),A0 ; redereference myPalette
Move.L (A3),A1 ; dereference CTab
Move D3,D0 ; copy size to a temp
SubQ #1,D0 ; ctSize is really last entry
; CHECK - what should we do with the seed? Get name of call from Ernie, again.
Clr.L ctSeed(A1) ; clear seed
Move D0,ctSize(A1) ; set size
Clr TransIndex(A1) ; this is not a device ColorTable (clear hi bit)
AddQ #ctTable,A1 ; bump color table to start
AddA #pmInfo,A0 ; bump palette to start
MoveQ #0,D1 ; clear index for pixel value
Bra.S CopyEnd ; jump to start of copy
CopyLoop Move D1,value(A1) ; set pixel value
Move.L ciRGB(A0),RGB(A1) ; copy red and green
Move ciRGB+blue(A0),RGB+blue(A1) ; copy blue
AddA.L #ciSize,A0 ; bump A0 to next ColorInfo
AddQ.L #ColorSpecSize,A1 ; bump A1 to next ColorSpec
AddQ #1,D1 ; bump pixel value
CopyEnd DBra D3,CopyLoop ; loop for all entries
GoHome MoveQ #0,D0 ; clear error condition
MoveM.L (SP)+,D3/A2-A3 ; restore registers <AWC>
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE ClearOne(eInfo:CiInfo; BasePtr:Ptr); LOCAL;
;
ClearOne PROC EXPORT
ParamSize equ 4 ; total bytes of params
eInfo equ ParamSize+8-4 ; entry to clear
BasePtr equ eInfo-4 ; pointer to PMgrHandle^^
VarSize equ 0
Link A6,#VarSize ; build stack frame
Move.L A2,-(SP) ; save a register
Move.L eInfo(A6),A0 ; get the ColorInfo address
Move ciPrivate(A0),D0 ; get the current link information
Clr ciFlags(A0) ; shut down any crap
Clr ciPrivate(A0) ; clear it
Move.L BasePtr(A6),A1 ; set up DevListPtr
Lea DevHandles(A1),A2 ; A2 points at DevHandles
AddA.L #LinkTabs,A1 ; A1 points at LinkTabs
NextLink BfExtU D0{19:5},D1 ; grab device number (0..31)
BfExtU D0{24:8},D2 ; grab index number (0..255)
Move.L (A2,D1.W*8),A0 ; get the device handle
Move.L (A0),A0 ; dereference it
Move.L gdPMap(A0),A0 ; get handle to pixmap
Move.L (A0),A0 ; dereference pixmap
Move.L pmTable(A0),A0 ; get handle to CTab
Move.L (A0),A0 ; dereference CTab
Cmp ctSize(A0),D2 ; is index number <= entries - 1?
Bhi.S IgnoreIt ; no => don't unreserve it
Clr ctTable+value(A0,D2.W*8) ; unreserve it
IgnoreIt Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Lea (A1,D1.L*4),A0 ; point A0 at next forward link
Move ForeLink(A0),D0 ; get next link
Clr.L ForeLink(A0) ; clear it for the next guy
Tst D0 ; is there another link to examine?
Bmi.S NextLink ; yes => go unlink it
Move.L (SP)+,A2 ; restore A2
Unlk A6 ; clean up our mess
Rtd #ParamSize ; go home
;---------------------------------------------------
;
; PROCEDURE CopyPalette(srcPalette,dstPalette: PaletteHandle; srcEntry,dstEntry,dstLength:
; INTEGER); INLINE $AAA1;
;
CopyPalette PROC EXPORT
ParamSize equ 14 ; total bytes of params
srcPalette equ ParamSize+8-4 ; source Palette handle
dstPalette equ srcPalette-4 ; destination palette handle
srcEntry equ dstPalette-2 ; source starting entry
dstEntry equ srcEntry-2 ; destination starting entry
dstLength equ dstEntry-2 ; length of the copy
TrimLen equ -2
VarSize equ TrimLen
Link A6,#VarSize ; build stack frame
MoveM.L D3-D4/A2-A4,-(SP) ; save registers
Move.L PMgrHandle,A4 ; get the main handle
CmpA.L #PMgrNil,A4 ; are we initialized?
Beq GoHome ; no => punt AWC.PB377
Move.L dstPalette(A6),A2 ; get destination palette
CmpA.L #Nil,A2 ; is it nil?
Beq GoHome ; can't deal with nil here either AWC.PB377
Move.L srcPalette(A6),A3 ; get source palette
CmpA.L #Nil,A3 ; is it nil?
Beq GoHome ; can't deal with a nil handle AWC.PB377
CmpA.L A2,A3 ; does source = destination?
Beq GoHome ; we can't handle this yet AWC.PB377
MoveQ #0,D0 ; clear D0
Move dstLength(A6),D0 ; get the length of the copy
Ble GoHome ; we can quit if it's too small
Move.L D0,D3 ; copy the length
Add SrcEntry(A6),D0 ; D0 is the required length of the source
Move.L (A3),A1 ; dereference source palette
Move pmEntries(A1),D1 ; get size of source palette
Sub D0,D1 ; D1, if negative, is how much we must trim D3
Bpl.S DontTrimSrc ; no => don't trim it
Add D1,D3 ; trim back the length of the copy AWC.PB530
DontTrimSrc Move.L (A2),A0 ; dereference the destination
Move pmEntries(A0),D4 ; get the length
Move DstEntry(A6),D0 ; calculate the potential new pmEntries
Add D3,D0 ; by adding the trimmed length
Cmp D4,D0 ; need we add handle room?
Ble.S BigEnough ; no => skip _SetHandleSize AWC.PB530
Move D0,D4 ; save new length
Move.L A2,A0 ; copy DstPalette
AddQ #1,D0 ; include palette header
Asl #4,D0 ; multiply by 16 bytes per entry | header
_SetHandleSize ; do it
Bne GoHome ; and quit if we couldn't do it AWC.PB377
Move.L (A2),A0 ; dereference the destination handle
Move D4,D2 ; make a copy of the new length
MoveQ #0,D1 ; clear the high word
Move PmEntries(A0),D1 ; this is where to start clearing
Sub D1,D2 ; this is now many to clear
Move D4,pmEntries(A0) ; save size
Lea PmInfo(A0),A1 ; point us at the start of the table
Asl #4,D1 ; this is the offset to the start of the clear
AddA.L D1,A1 ; bump A1 to the start of the clear
Bra.S ClearEnd ; jump to the DBra
; The main reason for clearing is so we can correctly detect and clear entries that are
; going to be clobbered.
ClearLoop Clr.L (A1)+ ; clear 16 bytes
Clr.L (A1)+
Clr.L (A1)+
Clr.L (A1)+
ClearEnd DBra D2,ClearLoop
BigEnough CmpA.L A2,A3 ; does SrcPalette = DstPalette?
Beq.S GoHome ; yes => can't handle this AWC.PB377
Move.L A3,-(SP) ; push the palette handle AWC.PB508
Bsr DirtySeeds ; clear the device seeds AWC.PB508
Move.L (A3),A1 ; dereference source palette
MoveQ #0,D0 ; clear the high word
Move DstEntry(A6),D0 ; get the first destination
Asl.L #4,D0 ; multiply by 16
Move.L (A2),A0 ; dereference destination palette again AWC.PB508
Lea PmInfo(A0,D0),A0 ; point A0 at the first destination
MoveQ #0,D1 ; clear the high word
Move SrcEntry(A6),D0 ; get the first source
Asl.L #4,D0 ; point A0 at the first destination
Lea PmInfo(A1,D0),A1 ; point A1 at the first source
Bra.S CopyEnd ; jump into the loop
CopyLoop Move ciPrivate(A0),D0 ; get the link info
Beq.S NoLinks ; no => it doesn't need clearing
MoveM.L A0-A1,-(SP) ; save registers
Move.L A0,-(SP) ; ciInfo to clear
Move.L (A4),-(SP) ; dereference PMgrHandle and push it
Jsr ClearOne ; clear the links
MoveM.L (SP)+,A0-A1 ; restore interesting registers
NoLinks Move.L ciRGB(A1),ciRGB(A0) ; copy first two words
Move.L ciRGB+Blue(A1),ciRGB+blue(A0) ; copy blue and usage
Move ciTolerance(A1),ciTolerance(A0) ; copy tolerance
Clr ciFlags(A0) ; clear the flags field
Clr ciPrivate(A0) ; clear the links field
AddA.L #CiSize,A0 ; bump both pointers
AddA.L #CiSize,A1
CopyEnd DBra D3,CopyLoop ; loop for (trimmed) length entries
GoHome MoveQ #0,D0 ; clear error code AWC.PB377
MoveM.L (SP)+,D3-D4/A2-A4 ; restore registers
Unlk A6 ; clear stack frame
Rtd #ParamSize ; strip parameters and go home
;---------------------------------------------------
;
; PROCEDURE UpdateDevice(DeviceNumber:INTEGER); Local;
;
; This here routine will do a setentries of deviceNumber on it's own color table.
; Also, it forces a redraw of that screen, including the menu bar.
; (This code was moved out of the tail of SetDev, so that ScatterDev could use it.)
; <dvb3>
;
UpdateDevice PROC EXPORT
UDVars RECORD {A6Link},DECREMENT
result DS.B 0 ;Result length: none
deviceNum DS.B 2 ;Input: device number
return DS.B 4
A6Link DS.B 4 ;old contents of A6
oldPort DS.B 4 ;pointer to old port
resultRect DS.B 8 ;a temp rectangle
sysUpdates DS.B 2 ;a temp boolean
linkSize DS.B 0 ;linky number
ENDR
WITH UDVars
LINK A6,#linkSize
MOVEM.L A0-A3/D0-D3,-(SP)
SUBQ #4,SP
_FrontWindow
MOVE.L (SP)+,D3 ; D3 = topmost window. Permanently.
Pea oldPort(A6) ; where to put current GrafPtr
_GetPort ; get it
MOVE.L PMgrHandle,A1 ; A1 = handle to palette data
MOVE.L (A1),A1 ; A1->palette data
MOVE deviceNum(A6),D0 ; D0 = device number to update
MOVE.L devHandles+devHandle(A1,D0.W*8),A2 ; A2 = handle to device to update
MOVE.L A2,A0 ; Put in A0, for devsetent
JSR DevSetEntries
Move.L (A2),A0 ; dereference it
Lea gdRect(A0),A2 ; get address of device rect into A2
Move gdFlags(A0),D0 ; get flags
BTst #MainScreen,D0 ; is it the main screen?
Beq.S NoMenuFix ; no => don't update the menu
Move.L MenuList,D0 ; get the MenuList handle; is it nil? AWC.PB508
Beq.S NoMenuFix ; yes => don't redraw the menu bar AWC.PB508
Move.L D0,A0 ; get ready to dereference it AWC.PB508
Tst.L (A0) ; has it been purged? AWC.PB508
Beq.S NoMenuFix ; yes => don't redraw the menu bar AWC.PB508
_DrawMenuBar ; redraw the menu bar AWC.PB508
NoMenuFix MoveQ #0,D0 ; we want no updates if no SysPalette AWC PB223
Move.L AppPalette,A0 ; fetch the application's palette, if any AWC.PB457
Move.L A0,D1 ; CmpA.L #Nil,A0; is it nil? AWC.PB457
Bne.S UseAppPltt ; no => use the application's palette AWC.PB457
MOVE.L PMgrHandle,A0
MOVE.L (A0),A0 ; A0 -> our data
Move.L SysPalette(A0),A0 ; fetch the system palette
Move.L A0,D1 ; CmpA.L #Nil,A0; is it nil? AWC.PB457
Beq.S NoSysP ; yes => we update
UseAppPltt Move.L (A0),A0 ; dereference AppPalette or SysPalette AWC.PB457
Move pmPrivate(A0),D0 ; get update information AWC PB224
And #$C000,D0 ; and it with the proper flags AWC PB224
NoSysP Move D0,sysUpdates(A6) ; set update information AWC PB224
JSR CheckForJuggler ; ÀAre we Juggling?
Bne.S NotJuggling ; no => handle updates the old way AWC PB224
Move.L A2,-(SP) ; push device rect on the stack AWC PB224
Move deviceNum(A6),-(SP) ; push PaletteMgr device number AWC PB224
Move sysUpdates(A6),-(SP) ; push default updates for old ports AWC PB224
Move #ColorInvalRect,-(SP) ; push the selector for _ColorInvalRect AWC PB224
_Juggler ; call Erich's disgusting C code AWC PB224
bra EndJuggling ; skip over the regular update code AWC PB224
NotJuggling Move.L WindowList,A3 ; get start of window list AWC PB224
CMPA #-1,A3 ; Window list there?
BEQ WLDone ; No, fini.
BRA EndWind ; Skip to end, for NIL check
WindowLoop Move sysUpdates(A6),D1 ; reset the default update value AWC.PB480
Move #CBackBit,D0 ; grab a constant AWC PB224
CmpA.L D3,A3 ; is it the "fore" window?
Bne.S NotCurrent ; no => check for background updates
Move #CForeBit,D0 ; grab a different constant AWC PB223
NotCurrent Tst.B wVisible(A3) ; is this window visible?
Beq NextWind ; no => do the next window <C864>
Tst PortBits+RowBytes(A3) ; is it a color window?
Bpl.S UseDefault ; no => handle an old style window AWC.PB480
Move.L GrafVars(A3),A0 ; get the extended variables handle
Move.L (A0),A0 ; dereference it
Move.L PmFgColor(A0),A0 ; get the window's palette, if any
CmpA.L #Nil,A0 ; is it nil?
Beq.S UseDefault ; yes => default to the system value AWC.PB480
Move.L (A0),A0 ; dereference the palette
Move pmPrivate(A0),D1 ; fetch the palette's update values AWC.PB480
UseDefault BTst D0,D1 ; does the caller want this update? AWC.PB480
Beq.S NextWind ; no => do the next window
; We now must check to see if the window we're examining intersects the device
; we're working upon. We'll GlobalToLocal the device rect and simultaneously
; intersect it with the window's portRect. If we detect an intersection then
; we'll have calculated the rectangle we'll need for the InvalRect. First we
; point A0 at the Bounds rect for the port so we can put DevRect in local space.
Lea PortBits(A3),A0 ; point A0 at potential bitmap AWC.PB480
Tst RowBytes(A0) ; bitmap or pixmap? AWC.PB480
Bpl.S GotBitmap ; no high bit in Rowbytes => bitmap AWC.PB480
Move.L BaseAddr(A0),A0 ; get Port's Pixmap handle AWC.PB480
Move.L (A0),A0 ; get Pixmap pointer AWC.PB480
GotBitmap Lea Bounds(A0),A0 ; advance A0 to Bounds rect AWC.PB480
Move Top(A2),D0 ; get device top AWC.PB480
Add Top(A0),D0 ; subtract bounds top AWC.PB480
Cmp PortRect+Bottom(A3),D0 ; is Dest.Top >= Port.Bottom? AWC.PB480
Bge.S NextWind ; yes => no intersection AWC.PB480
Move D0,resultRect+Top(A6) ; save it AWC.PB480
Move Left(A2),D0 ; get device left AWC.PB480
Add Left(A0),D0 ; subtract bounds left AWC.PB480
Cmp PortRect+Right(A3),D0 ; is Dest.Left >= Port.Right? AWC.PB480
Bge.S NextWind ; yes => no intersection AWC.PB480
Move D0,resultRect+Left(A6) ; save left AWC.PB480
Move Bottom(A2),D0 ; get bottom AWC.PB480
Add Top(A0),D0 ; subtract bounds top AWC.PB480
Cmp PortRect+Top(A3),D0 ; is Dest.Bottom <= Port.Top? AWC.PB480
Ble.S NextWind ; yes => no intersection AWC.PB480
Move D0,resultRect+Bottom(A6) ; save bottom AWC.PB480
Move Right(A2),D0 ; get right AWC.PB480
Add Left(A0),D0 ; subtract bounds left AWC.PB480
Cmp PortRect+Left(A3),D0 ; is Dest.Right <= Port.Left? AWC.PB480
Ble.S NextWind ; yes => no intersection AWC.PB480
Move D0,resultRect+Right(A6) ; save right AWC.PB480
Move.L A3,-(SP) ; push this window's pointer AWC.PB480
_SetPort ; make it the current port AWC.PB480
Pea resultRect(A6) ; move device rect (local) onto the stack AWC.PB480
_InvalRect ; invalidate it AWC.PB480
NextWind Move.L NextWindow(A3),A3 ; grab the next window in the list
EndWind CmpA.L #Nil,A3 ; is it nil?
Bne WindowLoop ; no => continue
Bsr RedrawDesktop ; redraw the desktop (uses A3) AWC.PB508
WLDone
EndJuggling Move.L oldPort(A6),-(SP) ; push old port
_SetPort ; restore old port
GoHome MoveQ #0,D0 ; clear error condition AWC.PB377
MoveM.L (SP)+,A0-A3/D0-D3 ; restore registers <AWC>
UNLK A6
RTD #result-return-4 ; bye.
;---------------------------------------------------
;
; PROCEDURE UpdateDevices(); LOCAL;
;
; Update all devices with bits in updateDevs.
UpdateDevices PROC EXPORT
MOVEM.L A0/D0-D1,-(SP)
CMPI.L #-1,WindowList ; Have Windows happened?
BEQ.S GoHome ; No=>skip this stuff
CMPI.L #-1,CurApName ; Is CurApName FFFFFFFF?
BEQ.S GoHome ; If so, we can't help yet.
MOVE.L PMgrHandle,A0
MOVE.L (A0),A0 ; A0->PMgr data
MOVE nDevs(A0),D0 ; D0 = number of devices
SUBQ #1,D0 ; less one for DBRAing
MOVE.L updateDevs(A0),D1 ; D1 = mask of devices to update
BEQ.S GoHome ; None. Bye.
CLR.L updateDevs(A0) ; Say they've been updated.
UpLoop BTST D0,D1 ; Update this one?
BEQ.S UpLoopEnd ; Nah.
MOVE D0,-(SP) ; Yah. Push device number (stack down 2)
JSR UpdateDevice
UpLoopEnd DBRA D0,UpLoop
GoHome MOVEM.L (SP)+,A0/D0-D1 ; fix regs
RTS
;---------------------------------------------------
;
; FUNCTION WhatPal(aWindow:WindowPtr):PaletteHandle; LOCAL; AAA2/5
;
; Given window in A2, return its palette, or appPalette, or even sysPalette
WhatPal PROC EXPORT
MOVE.L 4(SP),A0 ; A0 = aWindow
TST portBits+rowBytes(A0) ; An old port?
BPL.S @default ; Yes => go use sys- or app-palette
MOVE.L GrafVars(A0),A0
MOVE.L (A0),A0 ; A0->aux data
MOVE.L PmFgColor(A0),D0 ; D0 = specified Palette
BNE.S @goHome ; Nil? No => we got a palette
@default MOVE.L AppPalette,D0 ; Try the AppPalette
BNE.S @goHome ; Yes, got an AppP
MOVE.L PMgrHandle,A0
MOVE.L (A0),A0
MOVE.L SysPalette(A0),D0 ; D0 = System Palette
@goHome MOVE.L D0,8(SP)
RTD #4
;---------------------------------------------------
;
; PROCEDURE CalcDevs; LOCAL;
;
; Set DeviceSet(A6) and FrontSet(A6) to the bit-set of the
; devices that PaletteH(A6) affects.
;
CalcDevs PROC EXPORT
MOVEM.L D3-D7/A2-A3,-(SP) ; Restore registers
SUBQ #8,SP ; Make space for a temp rect
MOVE.L WindowList,A2 ; A2 = Windowlist walker
MoveQ #0,D3 ; clear device set
MoveQ #0,D4 ; clear front set
CLR.L -(SP) ; Space for result
_FrontWindow
MOVE.L (SP)+,D6 ; Keep the frontwindow in here.
BRA @wLoopEnd ; Branch to end of window walking
@wLoop TST.B wVisible(A2) ; A visible window?
; BEQ @wLoopNext ; No. Ignore it. <dvb11>:inv'ble w'dws can have colors
SUBQ #4,SP
MOVE.L A2,-(SP)
_WhatPal
MOVE.L (SP)+,A0
CMPA.L PaletteH(A6),A0 ; Same one we're activating?
BNE @wLoopNext ; No, don't check it.
LEA portBits(A2),A0 ; A0->bitmap
TST rowBytes(A0) ; Old port?
BPL @oldPort ; Yes=>skip pm dereference
MOVE.L baseAddr(A0),A0 ; A0 = pixmap handle
MOVE.L (A0),A0 ; A0->pixmap
@oldPort MOVE.L bounds(A0),D0 ; D0 = top, left of bounds rect
MOVE.L portRect(A2),D1 ; D1 = top, left of port rect
SUB D0,D1 ; D1Lo = global left
SWAP D0
SWAP D1
SUB D0,D1 ; D1Lo = global top
SWAP D0
SWAP D1
MOVE.L D1,WindowRect(A6) ; WindowRect topLeft in global
MOVE.L portRect+botRight(A2),D1 ; D1 = bottom, right of port rect
SUB D0,D1 ; D1Lo = global right
SWAP D0
SWAP D1
SUB D0,D1 ; D1Lo = global bottom
SWAP D1
MOVE.L D1,botRight+WindowRect(A6) ; WindowRect botRight in global
MOVE.L PMgrPtr(A6),A0 ; A0->Pmgr data
MOVE nDevs(A0),D5 ; D5 = device number
SUBQ #1,D5
LEA DevHandles(A0),A3 ; A3->List of devices
@dLoop MOVE.L DevHandle(A3,D5*8),A0 ; A0 = this device handle
MOVE.L (A0),A0 ; A0->this device
CLR -(SP) ; Space for result
PEA gdRect(A0) ; Push device rect
PEA WindowRect(A6) ; Push window rect
PEA 10(SP) ; Push throwaway result rect
_SectRect
TST (SP)+ ; Any intersection?
BEQ.S @dLoopEnd ; No=>advance to next gDevice
BSET D5,D3 ; Set this bit of deviceSet
TST.B wHilited(A2) ; Is this window hilited?
BEQ.S @notFront ; If not, can't be frontish
CMP.L A2,D6 ; Is this window the FrontWindow?
BNE.S @wasntFront ; No => go here
MOVE.L A2,DevFrontMost(A3,D5*8) ; Yes => save it.
BRA.S @wasFront
@wasntFront CMPA.L DevFrontMost(A3,D5*8),A2 ; was it previously frontmost?
BNE.S @notFront ; No, not front at all.
@wasFront BSET D5,D4 ; Set this bit of FrontSet
@notFront
@dLoopEnd DBRA D5,@dLoop ; Try next device
@wLoopNext MOVE.L NextWindow(A2),A2 ; Get next window
@wLoopEnd MOVE.L A2,D0 ; NIL window?
BNE @wLoop ; No=>Loop!
MOVE.L D3,DeviceSet(A6) ; Save device set
MOVE.L D4,FrontSet(A6) ; Save frontmost set
ADDQ.L #8,SP ; Lose temp rectangle
MOVEM.L (SP)+,D3-D7/A2-A3 ; Restore registers
RTS
;---------------------------------------------------
;
; PROCEDURE UnhookDevice(whichDevice:deviceHandle);
;
; InitGDevice ought to call this routine. When a device is initialized, release any animated
; entries, and give it our idea of an appropriate clut.
UnhookDevice PROC EXPORT
ParamSize equ 4 ; total bytes of params
whichDevice equ ParamSize+8-4 ; device we're unlinking
Link A6,#spVarSize ; build stack frame
MOVEM.L D2-D4/A2,-(SP)
Move.L PMgrHandle,A0 ; get global handle
CmpA.L #PMgrNil,A0 ; is it nil?
Beq.S GoHome ; skip it
Move.L (A0),A0 ; dereference PMgrHandle
Move nDevs(A0),D3 ; are there any devices?
LEA DevHandles(A0),A1 ; A1 = start of list of devices, D4=count
MOVE.L whichDevice(A6),D1 ; D1 = device handle to fix release links of
SUBQ #1,D3 ; for DBRA (nDevs says we've got some devs)
FindDevLoop CMP.L DevHandle(A1,D3.W*8),D1 ; Is this the device?
BEQ.S FoundDevice
DBRA D3,FindDevLoop
BRA.S GoHome ; It's not a device we know about.
FoundDevice LSL.W #8,D3 ; Shift device number into high bits
MOVE.L D1,A2 ; A2 = device we're zapping
MOVE.L (A2),A2 ; dereference device
MOVE.L gdPMap(A2),A2 ; A2 = PixMapHandle
MOVE.L (A2),A2 ; dereference pmhandle
MOVE.L pmTable(A2),A2 ; A2 = cluthandle
MOVE.L (A2),A2 ; dereference that, too
MOVE #255,D4 ; We'll just unlink all 256 entries of the linktab.
ZapLoop MOVE.B D4,D3
MOVE.W D3,-(SP) ; Push combinded index and device
_ZapLinks ; Unlink device/index combo
ZapLoopEnd DBRA D4,ZapLoop
SUB #2,SP ; Space for result
MOVE.L D1,-(SP) ; Push device handle
JSR CheckDeviceColors ; Look for the right colors
TST (SP)+ ; Anything reallocated?
BEQ.S GoHome ; No=>nothing
CLR.L D0
LSR.W #8,D3 ; Get back device number
BSET D3,D0 ; D0 = 1 bit set in the device's position
OR.L D0,scatterDevs(A0) ; Tell ourselves to deal with that device.
MOVE #1,-(SP)
JSR ScatterDevices ; And scatter entries.
;!!! MOVE D3,-(SP) ; Push device number
;!!! JSR UpdateDevice ; Update this device.
GoHome MOVEM.L (SP)+,D2-D4/A2
UNLK A6
RTD #paramSize ; Bus on out of here.
;---------------------------------------------------
;
; PROCEDURE UnreserveDevices(PMgrPtr,PalettePtr,Devmask);
;
; Call me to unreserve entries when a palette has moved from one place to another.
; We have ActivatePalettes A6 frame, also, on entry, we have
; A0->Pmgr data, A1->palette, D0 = devmask
; <dvb3>
UnreserveDevices PROC EXPORT
MOVEM.L A2-A4/D1-D4,-(SP)
LEA LinkTabs(A0),A2 ; A2 -> linktabs
MOVE pmEntries(A1),D1 ; D1 = loop variable
LEA pmInfo(A1),A3 ; A3 = walking ColorInfo pointer
CLR.L D4 ; D4 = device mask for later scattering
BRA.S entryEnd
entryLoop MOVE ciPrivate(A3),D2 ; D2 = LinkTab entry (if any)
BPL.S nextEntry ; If positive, it owns no entries.
devLoop BFEXTU D2{19:5},D3 ; D3 = device number
BTST D3,D0 ; A device we should 'clear'?
BEQ.S nextDev ; No, keep walking
BSET D3,D4 ; Mark device for scattering
MOVE.L D0,-(SP) ; preserve D0
MOVE D2,-(SP) ; Push Device/Index
_ZapLinks ; Unlink it
MOVE.L (SP)+,D0 ; restore D0
MOVE.L DevHandles+DevHandle(A0,D3*8),A4 ; A4 = device handle
BFEXTU D2{24:8},D3 ; D3 = index
Move.L (A4),A4 ; dereference it
Move.L gdPMap(A4),A4 ; get handle to pixmap
Move.L (A4),A4 ; dereference pixmap
Move.L pmTable(A4),A4 ; get handle to CTab
Move.L (A4),A4 ; dereference CTab
Cmp ctSize(A4),D3 ; is index number <= entries - 1?
Bhi.S nextDev ; no => don't unreserve it
MOVE #ctScatterVal,ctTable+value(A4,D3.W*8) ; unreserve it, mark scatterbit <dvb3>
nextDev AND #$1FFF,D2 ; Mask off the key bits
MOVE ForeLink(A2,D2.W*4),D2 ; Get next link item
BMI.S devLoop ; End of list, eh?
nextEntry ADDA #ciSize,A3
entryEnd DBRA D1,entryLoop
OR.L D4,scatterDevs(A0)
MOVEM.L (SP)+,A2-A4/D1-D4
RTS
;---------------------------------------------------
;
; PROCEDURE ZapLinks(myIndex:integer); LOCAL; AAA2/4
;
; If index myIndex (combined device and index) is linked by someone, break the link
; and mark it free. Decrement the "reserves" count of the palette who
; owns the index. Pass myIndex with device in high bits, index in low bits.
; (This code was moved out of Pillage <dvb>)
; (See how we courteously restore ALL registers)
ZapLinks PROC EXPORT
ZLVars RECORD {A6Link},DECREMENT
result DS.B 0 ;Result length: none
myIndex DS.B 2 ;Input: device number and index to unlink
return DS.B 4
A6Link DS.B 4 ;old contents of A6
linkSize DS.B 0 ;linky number
ENDR
WITH ZLVars
LINK A6,#linkSize
MOVEM.L A0-A2/D0-D4,-(SP)
MOVE.L PMgrHandle,A1
MOVE.L (A1),A1 ; A1->PMgrData
LEA LinkTabs(A1),A0 ; A0->Link Tables
MOVE.L PListHandle(A1),A2 ; A2 = palette list handle
MOVE.L (A2),A2 ; A2 -> palette info list
MOVE myIndex(A6),D0 ; D0 = tricky link
AND #$1FFF,D0 ; clear key bits
MOVE D0,D1
LSR #8,D1 ; D1 = device number
MOVE.L DevHandles(A1,D1*8),A1 ; A1 = device handle
MOVE.L (A1),A1 ; A1->device
MOVE.L gdPMap(A1),A1 ; A1 = pixmap handle
MOVE.L (A1),A1 ; A1->pixmap
MOVE.L pmTable(A1),D1 ; D0 = color table for this device
BEQ.S @a ; Skip this if none
MOVE.L D1,A1 ; A1 = color table handle
MOVE.L (A1),A1 ; A1 -> color table
CLR D1
MOVE.B D0,D1 ; We need to clear the upper bits
CMP ctSize(A1),D1 ; Index in range? <dvb - was D0, WRONG!>
BHI.S @a ; No=>skip this
BCLR #ctReserveBit,ctTable+value(A1,D1*8) ; unreserve!
@a
Move ForeLink(A0,D0.W*4),D3 ; get forward links
BEQ GoHome ; Hey! this link was unowned anyhow! <dvb3>
Move BackLink(A0,D0.W*4),D4 ; get backward links
Clr.L (A0,D0.W*4) ; clear the links away
Tst D3 ; examine forward link
Bmi.S MultiLinks1 ; if < 0 we have more than one assigned
Tst D4 ; examine backward link
Bmi.S MultiLinks2 ; if < 0 we have more than one assigned
; This was a quickie. D3 contains the palette number, D4 the entry number. All we
; need do is tell the palette it no longer has it.
And #$1FFF,D3 ; clear key bits
SubQ #1,Reserves(A2,D3*8) ; it has one less entry reserved
Move.L PaletteRef(A2,D3*8),A0 ; get the palette
Move.L (A0),A0 ; dereference it
And.L #$00001FFF,D4 ; clear high word and key bits
Lsl.L #4,D4 ; make it an offset to the ColorInfo
Clr pmInfo+ciPrivate(A0,D4.L) ; clear the link
Bra GoHome ; we did it!
; The forward link goes somewhere. See if the backward one does too. If so,
; jump to BothLinks.
MultiLinks1 Tst D4 ; examine backward link
Bmi.S BothLinks ; both of them go somewhere
; The forward link goes somewhere, but the backward one does not. We must remember
; the first forward link so we can copy it into the palette, then we advance
; forward by one, copy the palette entry into that, and continue searching until we find
; out what palette this is.
Move D3,D0 ; remember the forward link
BfExtU D3{19:5},D1 ; grab device number (0..31)
BfExtU D3{24:8},D2 ; grab index number (0..255)
Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Lea (A0,D1.L*4),A1 ; point A1 at next forward link
Move D4,BackLink(A1) ; copy the back link
Move ForeLink(A1),D3 ; get next link
Bpl.S GotPalette1 ; if > 0, we've found the palette
MultiFLoop BfExtU D3{19:5},D1 ; grab device number (0..31)
BfExtU D3{24:8},D2 ; grab index number (0..255)
Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Move ForeLink(A0,D1.L*4),D3 ; get next link; is it positive?
Bmi.S MultiFLoop ; no => continue
GotPalette1 And #$1FFF,D3 ; clear key bits
SubQ #1,Reserves(A2,D3*8) ; it has one less entry reserved
Move.L PaletteRef(A2,D3*8),A0 ; get the palette
Move.L (A0),A0 ; dereference it
And.L #$00001FFF,D4 ; clear high word of entry
Lsl.L #4,D4 ; make it an offset to the ColorInfo
Move D0,pmInfo+ciPrivate(A0,D4.L) ; set a new link
Bra.S GoHome ; we did it!
; The backward link goes somewhere, but the forward one does not. We must advance
; backward by one, copy the palette id into it, and continue searching until we find out
; what palette this is.
MultiLinks2 BfExtU D4{19:5},D1 ; grab device number (0..31)
BfExtU D4{24:8},D2 ; grab index number (0..255)
Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Lea (A0,D1.L*4),A1 ; point A1 at next backward link
Move D3,ForeLink(A1) ; copy the forward link
Move BackLink(A1),D4 ; get next link
Bpl.S GotPalette2 ; if > 0, we've found the palette
MultiBLoop BfExtU D4{19:5},D1 ; grab device number (0..31)
BfExtU D4{24:8},D2 ; grab index number (0..255)
Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Move BackLink(A0,D1.L*4),D4 ; get next link; is it positive?
Bmi.S MultiBLoop ; no => continue
Bra.S GotPalette2 ; share common code
; We're in the middle of the list somewhere. We'll step one backward and copy
; the forelink from the current entry, then we'll step one foreward and copy
; the backlink from the current entry. Then we'll keep going forward until we
; find the palette. All we need do is decrement its reference count, so we don't
; need the entry number.
BothLinks BfExtU D4{19:5},D1 ; grab device number (0..31)
BfExtU D4{24:8},D2 ; grab index number (0..255)
Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Lea (A0,D1.L*4),A1 ; point A1 at next backward link
Move D3,ForeLink(A1) ; copy the forward link
BfExtU D3{19:5},D1 ; grab device number (0..31)
BfExtU D3{24:8},D2 ; grab index number (0..255)
Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Lea (A0,D1.L*4),A1 ; point A1 at next foreward link
Move D4,BackLink(A1) ; copy the backward link
Move ForeLink(A1),D3 ; get next foreward link
Bpl.S GotPalette2 ; if > 0, we've found the palette
BothLoop BfExtU D3{19:5},D1 ; grab device number (0..31)
BfExtU D3{24:8},D2 ; grab index number (0..255)
Lsl #8,D1 ; calculate offset to link table/4
Add D2,D1 ; offset to entry/4
Move ForeLink(A0,D1.L*4),D3 ; grab next forward link
Bmi.S BothLoop ; if < 0, we keep looking
GotPalette2 And #$1FFF,D3 ; clear away key bits
SubQ #1,Reserves(A2,D3*8) ; it has one less entry reserved
GoHome MOVEM.L (SP)+,A0-A2/D0-D4
UNLK A6
RTD #result-return-4 ; go home
;---------------------------------------------------
;
; PROCEDURE ResizePalette(srcPalette:PaletteHandle; dstSize:INTEGER); AAA2/3;
;
; Set the number of entries in the palette, and properly dispose of some
; of them if the palette is shrinking.
ResizePalette PROC EXPORT
RPVars RECORD {A6Link},DECREMENT
result DS.B 0 ; Result: none
srcPal DS.B 4 ; input: palette handle
dstSize DS.B 2 ; input: new size for palette
return DS.B 4
A6Link DS.B 4 ; old contents of A6
linkSize DS.B 0 ;linky number
ENDR
WITH RPVars
LINK A6,#linkSize
MOVEM.L A2/D3-D4,-(SP) ; save 'em.
IF (forRom OR theFuture) THEN
; clear out d3,d4 for later use
moveq #0,d3 ;<SM2> FM This ensures that the high
move.l d3,d4 ;<SM2> FM word is zeroed out before the compare
ENDIF
MOVE.L srcPal(A6),A0 ; A0 = palette we're resizing
MOVE.L A0,D0
ADDQ.L #1,D0 ; Was it Ptr(-1)? The App Palette?
BNE.S @foundPal ; No=>it's a real one
MOVE.L AppPalette,A0 ; Get the 'app palette'
@foundPal MOVE.L (A0),A2 ; A2->the palette
MOVE dstSize(A6),D3 ; D3 = new size for palette
MOVE pmEntries(A2),D4 ; D4 = old size of palette
CMP D4,D3 ; Compare new size to old size
BEQ.S @goHome ; The same, do nothing
BHI.S @sizeIt ; It's bigger, resize and fix new entries
_HLock ; If we're shrinking, we have to lose entries
MOVE.L (A0),A2 ; A2->locked palette
MOVE D4,D0 ; D0 = old size of palette
LSL #4,D0 ; Multiply by size of colorInfos
LEA pmInfo(A2,D0.W),A2 ; A2->just past last colorInfo
@loseLoop SUBA #ciSize,A2 ; Bump A2 down to next colorInfo
SUBQ #1,D4 ; Bump D4 down to next entry number
MOVE ciUsage(A2),D0 ; D0 = usage for this entry
ANDI #pmTolerant+pmAnimated,D0 ; Anything we care about?
BEQ.S @loseEnd ; No, continue
MOVE.L srcPal(A6),-(SP) ; Yes => set usage to courteous, before death
MOVE D4,-(SP) ; Push entry number
CLR.L -(SP) ; 0 usage, 0 tolerance (its the law)
_SetEntryUsage
@loseEnd CMP D4,D3
BNE.S @loseLoop ; Work right down to new size
MOVE.L srcPal(A6),A0 ; Get handle back
_HUnlock
@sizeIt MOVE D3,D0 ; D0 = new number of entries
EXT.L D0 ; long, for resize
LSL.L #4,D0 ; times size of colorInfos
ADD.L #pmInfo,D0 ; Plus size of header
_SetHandleSize
BNE.S @goHome ; Failed, go home.
MOVE.L (A0),A2 ; A2->palette
MOVE D3,pmEntries(A2) ; Set new palette size
CMP.w D3,D4 ; Was old size smaller? <KON 17May90>
BHS.S @goHome ; old size (D4) was bigger, or the same
SUB.L D4,D3 ; D3 = difference in sizes
LSL #4,D4 ; Get D4 to size*colorInfo size
LEA pmInfo(A2,D4),A0 ; A0->first newly added entry
LSL #2,D3 ; D3 = difference in sizes in longwords
SUBQ #1,D3 ; Less one, for DBRA
@clrLoop CLR.L (A0)+ ; Clear a long
DBRA D3,@clrLoop ; Keep on clearing
@goHome MOVEM.L (SP)+,A2/D3-D4
UNLK A6
RTD #result-return-4
;---------------------------------------------------
;
; PROCEDURE RestoreDeviceClut(aGDev:gDevice); AAA2/2;
;
; Set the specified device back to its default clut, based on depth
; and color/gray. If direct, ignore it. Actually, "UnhookDevice"
; does all the real work here, we just provide a loop to do it
; to all the devices if NIL is passed.
;
RestoreDeviceClut PROC EXPORT
TST.L 4(SP) ; Was NIL passed?
BNE UnhookDevice ; Yes => just pass on to Unhookdevice
MOVE.L A3,-(SP) ; Save a walking register
MOVE.L deviceList,D0 ; Get head of devicelist
BRA.S @devLoopEnd ; Go to end of list
@devLoop MOVE.L D0,A3
MOVE.L A3,-(SP) ; Push device handle
BSR UnhookDevice
MOVE.L (A3),A3 ; Dereference gDev handle
MOVE.L gdNextGD(A3),D0 ; Get next gdev handle
@devLoopEnd BNE.S @devLoop ; NIL?
MOVE.L (SP)+,A3 ; Yeah, fix register.
RTD #4 ; We're out, lose input handle.
;---------------------------------------------------
;
; PROCEDURE NewHiliteColor; AAA2/11;
;
; Call here when the hilite-color has been changed. Screens will be appropriately
; zapped.
NewHiliteColor PROC EXPORT
MOVE.L PMgrHandle,D1 ; PMgr active?
BEQ.S cancel
MOVE.L D1,A1
MOVE.L (A1),A1 ; A1->PMgr
MOVE.L sevenCluts+8(A1),D0 ; Have we a two-bit hilite clut?
BEQ.S noTwoBit ; Nah, we're fine
CLR.L sevenCluts+8(A1) ; Okay, it's nil.
MOVE.L D0,A0 ; Yes=>toss it, we'll rebuild.
_DisposHandle
noTwoBit MOVE.L D1,A1 ; A1 = PMgr Handle
MOVE.L (A1),A1 ; A1->PMgr
MOVE.L sevenCluts+16(A1),D0 ; Have we a four-bit hilite clut?
BEQ.S noFourBit ; Nah, we're fine
CLR.L sevenCluts+16(A1) ; Okay, it's nil.
MOVE.L D0,A0 ; Yes=>toss it, we'll rebuild.
_DisposHandle
noFourBit
JSR CheckAllDeviceCluts ; make sure everyone has new HiliteColor
CLR -(SP) ; No setentries on scatter
JSR ScatterDevices ; put some colors out there
JSR UpdateDevices ; Send those InvalRects arounds.
cancel RTS ; bye.
;---------------------------------------------------
;
; PROCEDURE SaveFore(VAR x:ColorSpec); AAA2/13;
; PROCEDURE SaveBack(VAR x:ColorSpec); AAA2/14;
;
; Return a colorspec with the following coding:
; value = 0 - rgb is an rgb color
; value = 1 - rgb.red is the previous palette entry number
;
SaveFore PROC EXPORT
EXPORT SaveBack
MOVEQ #0,D0 ; Tell ourselves it's a Fore
BRA.S save
SaveBack MOVEQ #1,D0 ; Tell ourselves it's a Back
save MOVE.L 4(SP),A1 ; A1->colorSpec to return data in
Move.L GrafGlobals(A5),A0 ; get the QuickDraw globals pointer
Move.L ThePort(A0),A0 ; point at the port
Tst PortBits+Rowbytes(A0) ; is it a new port?
Bpl.S @saveRGB ; no => punt
MOVE.L GrafVars(A0),D1 ; Get aux handle <dvb9>
BEQ.S @SaveRGB ; Not there? puntit
MOVE.L D1,A0 ; <dvb9>
MOVE.L (A0),A0 ; A0->aux data
BTST D0,pmFlags+1(A0) ; Test the appropriate bit fore PM
BEQ.S @SaveRGB ; Okay, it wasn't a PmXxxxColor
MOVE #1,value(A1) ; value=1: a PM save
TST D0 ; Fore or back call
BEQ.S @pmFore
MOVE pmBkIndex(A0),rgb+red(A1) ; Save back entry number
BRA.S @goHome
@pmFore MOVE pmFgIndex(A0),rgb+red(A1) ; Save fore entry number
@goHome RTD #4
@SaveRGB CLR value(A1) ; value=0: an RGB save
PEA rgb(A1) ; Push pointer to rgb
TST D0 ; Fore or back?
BEQ.S @rgbFore
_GetBackColor
BRA.S @goHome
@rgbFore _GetForeColor
BRA.S @goHome
;---------------------------------------------------
;
; PROCEDURE RestoreFore(VAR x:ColorSpec); AAA2/15;
; PROCEDURE RestoreBack(VAR x:ColorSpec); AAA2/16;
;
; Set the fore/back color from a colorspec
; with the following coding:
; value = 0 - rgb is an rgb color
; value = 1 - rgb.red is the previous palette entry number
;
RestoreFore PROC Export
EXPORT RestoreBack
MOVE.L 4(SP),A1 ; A1->Spec to restore
TST (A1)+ ; RGB or PM color?
BNE.S forePM ; PM => do that
PEA (A1) ; RGB => do that
_RGBForeColor
goHome RTD #4
forePM MOVE (A1),-(SP)
_PMForeColor
BRA.S goHome
RestoreBack
MOVE.L 4(SP),A1 ; A1->Spec to restore
TST (A1)+ ; RGB or PM color?
BNE.S backPM ; PM => do that
PEA (A1) ; RGB => do that
_RGBBackColor
BRA.S goHome
backPM MOVE (A1),-(SP)
_PMBackColor
BRA.S goHome
;---------------------------------------------------
;
; PROCEDURE ReleaseList(selection:ReqListRec); AAA2/18;
;
; Have the palette manager release any entries in the ReqListRec.
; This is a pointer to a list of device indices in the same format
; as is passed to RestoreEntries. RestoreEntries should call this
; routine when passed NIL for the color table.
;
; Preserves standard toolbox regs: D3-D7/A2-A4
;
ReleaseList PROC EXPORT
TST.L PMgrHandle
BEQ.S @Nothing ; No PMgr, do nothing.
MOVEM.L D3/D4/A2,-(SP) ; save regs, stack down 12
MOVE.L 16(SP),A2 ; A2->list of entries
MOVE.L PMgrHandle,A0
MOVE.L (A0),A0
MOVE nDevs(A0),D0 ; D0 = number PMgr known devs
LEA DevHandles(A0),A0 ; A0->list of PMgr known devs
CLR D3
MOVE.L theGDevice,D1
@findDev CMP.L DevHandle(A0,D3*8),D1 ; Is it this device?
BEQ.S @foundDev ; Yes => go zap some links.
ADDQ #1,D3
CMP D0,D3
BLO @findDev
BRA.S @GoHome ; Ran out of devices
@foundDev LSL #8,D3 ; Get device in higher bits
MOVE (A2)+,D4 ; D4=number of indices to clear
@zapLoop MOVE (A2)+,D0
MOVE.B D0,D3
MOVE D3,-(SP) ; Push device/index combo
_ZapLinks
DBRA D4,@zapLoop
@goHome MOVEM.L (SP)+,D3/D4/A2
@Nothing RTD #4
;---------------------------------------------------
;
;FUNCTION FindModeID(gd:GDHandle; depth: INTEGER):INTEGER;
;
; return the mode number (128-133 or so) for
; the requested depth on device "gd,"
; or zero if no such mode available.
; (internal routine for SetDepth and HasDepth
;
FindModeID FUNC Export
RTS
;---------------------------------------------------
;
;FUNCTION SetDepth(gd:GDHandle; depth: INTEGER; whichFlags:SHORT; flags:SHORT):OSErr; AAA2/19
;
;
SetDepth FUNC EXPORT
whichMask EQU $00FF ; only allow user to change low byte of gdFlags
SDVars RECORD {A6Link},DECREMENT
result DS.B 2 ; boolean result
gd DS.B 4 ; input: GDevice to set
depth DS.B 2 ; input: depth to set to
whichFlags DS.B 2 ; which GDFlags to affect
flags DS.B 2 ; input: various flags
return DS.B 4 ; return address on stack
A6Link DS.B 4 ; link
r DS.B 4 ; regionhandle
oldPort DS.B 4 ; previous port
myRect DS.B 8 ; rectangle for little black corners
moreStuff DS.B 10 ; not sure what for?
linkSize DS.B 0 ; size of record
ENDR
WITH SDVars
LINK A6,#linkSize
MOVEM.L A2-A3/D3-D5,-(SP) ; <6>
MOVE #paramErr,result(A6) ; default to failure!
MOVE.B #1,myRect+6(A6)
MOVEQ #0,D0
MOVE depth(A6),D0
MOVE.L D0,r(A6)
CLR -(SP)
MOVE.L gd(A6),-(SP)
CLR.L -(SP)
MOVE.L r(A6),-(SP)
PEA oldPort(A6)
CLR.L -(SP)
PEA myRect+7(A6)
MOVE #$C12,D0 ; _DMRemoveDisplay
DC.W $ABEB
TST (SP)+
BNE.S @goHome
MOVE.L oldPort(A6),D0
BTST.L #1,D0
BNE.S @goHome
MOVE.L gd(A6),A1
MOVE.L (A1),A1
MOVE whichFlags(A6),D0 ; D0 = mask of flags to change
ANDI #whichMask,D0 ; D0 = only the ones we let them change
MOVE D0,D1 ; D1 = mask of flags to change
AND flags(A6),D1 ; D1 = only the flags to change
NOT D0 ; D0 = mask of flags to keep
AND gdFlags(A1),D0 ; D0 = all the unchanged gdFlags
OR D1,D0 ; D0 = new gdFlags word
MOVE D0,gdFlags(A1) ; Put back into gDevice
CLR -(SP)
MOVE.L gd(A6),-(SP)
CLR.L -(SP)
PEA r(A6)
CLR.L -(SP)
CLR.L -(SP)
MOVE #$A11,D0 ; _DMEnableDisplay
DC.W $ABEB
MOVE (SP)+,result(A6)
@goHome
MOVEM.L (SP)+,A2-A3/D3-D5
UNLK A6
RTD #result-return-4
;---------------------------------------------------
;
;FUNCTION HasDepth(gd:GDHandle; depth: INTEGER; whichFlags:SHORT; flags:SHORT):BOOLEAN;
;
;
HasDepth FUNC EXPORT
whichMask EQU $FFFE ; the lowest bit is settable, else fail
SDVars RECORD {A6Link},DECREMENT
result DS.B 2 ; 18 $12 boolean result
gd DS.B 4 ; 14 $E input: GDevice to set
depth DS.B 2 ; 12 $C input: depth to set to
whichFlags DS.B 2 ; 10 $A which GDFlags to affect
flags DS.B 2 ; 8 $8 input: various flags
return DS.B 4 ; 4 $4 return address on stack
A6Link DS.B 4 ; link
myDepth DS.B 4
moreStuff DS.B 24
linkSize DS.B 0 ; size of record
ENDR
WITH SDVars
LINK A6,#linkSize
CLR result(A6) ; default to failure!
MOVE whichFlags(A6),D0 ; D0 = mask of flags to change
AND flags(A6),D0 ; D0 = new flags to set
AND #whichMask,D0 ; D0 = all the bits we can't change
BNE @goHome ; User tried to set bits we don't yet do!
MOVEQ #0,D0
MOVE depth(A6),D0
MOVE.L D0,myDepth(A6)
CLR moreStuff+0(A6)
CLR.L moreStuff+2(A6)
CLR moreStuff+6(A6)
CLR.L moreStuff+8(A6)
CLR.L moreStuff+12(A6)
CLR -(SP)
MOVE.L gd(A6), -(SP)
PEA moreStuff(A6)
MOVE.L myDepth(A6), -(SP)
PEA -$C(A6)
CLR.L -(SP)
MOVE #$AF3,D0 ; unknown _DisplayDispatch selector
DC.W $ABEB
TST (SP)+
BNE.B @goHome
MOVEQ.L #$7F, D0
MOVEQ.L #0, D1
MOVE depth(A6), D1
CMP.L D1, D0
BLT.B @whaaa
MOVE $C(A6), D0
CMP -$C(A6), D0
BNE.B @goHome
@whaaa MOVE -$1C(A6), $12(A6)
@goHome
UNLK A6
RTD #result-return-4
;---------------------------------------------------
;
;FUNCTION PMgrVersion:INTEGER; AAA2/21;
;
;
PMgrVersion FUNC EXPORT
MOVE #PMgrVersNum,4(SP) ; stash it above the return address
CLR D0 ; no error
RTS
;---------------------------------------------------
;
;PROCEDURE SetPaletteUpdates(PaletteHandle, Integer); AAA2/22;
;
; Set the type of color updates that this palette will receive,
; from the xxxPaletteUpdates constants.
;
; (We don't check for nil being passed; it must be a real palette).
SetPaletteUpdates PROC EXPORT
SPUVars RECORD {A6Link},DECREMENT
result DS.B 0 ; no result
srcPalette DS.B 4 ; input: Palette to set
updateMode DS.B 2 ; input: new update level
return DS.B 4 ; return address on stack
A6Link DS.B 4 ; link
linkSize DS.B 0 ; size of record
ENDR
WITH SPUVars
LINK A6,#linkSize
MOVE.L srcPalette(A6),A0
MOVE.L (A0),A0 ; A0->palette
MOVE updateMode(A6),D0
LSL #8,D0 ; Move those two bits high
LSL #6,D0 ; Move those two bits high
AND #$C000,D0
MOVE pmPrivate(A0),D1
AND #$3FFF,D1
OR D0,D1
MOVE D1,pmPrivate(A0)
UNLK A6
CLR.L D0 ; No error
RTD #result-return-4
;---------------------------------------------------
;
;FUNCTION GetPaletteUpdates(PaletteHandle, Integer):INTEGER; AAA2/23;
;
; inverse of SetPaletteUpdates
;
GetPaletteUpdates PROC EXPORT
GPUVars RECORD {A6Link},DECREMENT
result DS.B 2 ; result: update level
srcPalette DS.B 4 ; input: Palette to look at
return DS.B 4 ; return address on stack
A6Link DS.B 4 ; link
linkSize DS.B 0 ; size of record
ENDR
WITH GPUVars
LINK A6,#linkSize
MOVE.L srcPalette(A6),A0
MOVE.L (A0),A0
MOVE pmPrivate(A0),D0
LSR #8,D0
LSR #6,D0
MOVE D0,result(A6)
UNLK A6
CLR.L D0
RTD #result-return-4
;---------------------------------------------------
;
; FUNCTION GetGray(device: GDHandle, backGround: RGBColor;
; VAR foreGround: RGBColor): BOOLEAN; AAA2/25;
;
GetGray PROC EXPORT
GGVars RECORD {A6Link},DECREMENT
result DS.B 2 ; result: BOOLEAN
device DS.B 4 ; device to check
bGround DS.B 4 ; input: backGound Color
fGround DS.B 4 ; variable parameter foreGround Color
return DS.B 4 ; return address on stack
A6Link DS.B 4 ; link
oldGD DS.B 4 ; GDevice before we started
realFore DS.B 6 ; actual RGBValue of foreGround
realBack DS.B 6 ; actual RGBValue of backGround
calcAvg DS.B 6 ; calculated average
realAvg DS.B 6 ; real average
linkSize DS.B 0 ; size of record
ENDR
WITH GGVars
LINK A6,#linkSize
MOVE.L A2, -(SP)
CLR.B result(A6) ; Assume false
MOVE.L TheGDevice, oldGD(A6)
TST.L device(A6)
BEQ.S @theDeviceSet
MOVE.L device(A6), TheGDevice
@theDeviceSet
SUBQ #4, SP
MOVE.L bGround(A6), -(SP)
_Color2Index
PEA realBack(A6)
_Index2Color
SUBQ #4, SP
MOVE.L fGround(A6), -(SP)
_Color2Index
PEA realFore(A6)
_Index2Color
LEA realFore(A6), A0
LEA realBack(A6), A1
LEA calcAvg(A6), A2
MOVEQ #2, D1
@addLoop MOVE.W (A0)+, D0
ADD.W (A1)+, D0
ROXR #1, D0
BMI.S @lighterThanHalf
ADDQ #2, D0
@lighterThanHalf
MOVE.W D0, (A2)+
DBRA D1, @addLoop
SUBQ #4, SP
PEA calcAvg(A6)
_Color2Index
PEA realAvg(A6)
_Index2Color
MOVE.L oldGD(A6), TheGDevice
SUBQ #2,SP
PEA realFore(A6)
PEA realAvg(A6)
JSR DeltaRGB
SUBQ #2,SP
PEA realBack(A6)
PEA realAvg(A6)
JSR DeltaRGB
SUBQ #2,SP
PEA calcAvg(A6)
PEA realAvg(A6)
JSR DeltaRGB
MOVE (SP)+,D0 ; D0 = delta to self
MOVE (SP)+,D1 ; D1 = delta to back
MOVE (SP)+,D2 ; D2 = delta to fore
LSR #1,D1 ; bias to prefer pattern
LSR #1,D2 ; unless there's a good match
CMP D1,D0 ; Are we closer to back?
BHS.S @twoColor ; yes => dither
CMP D2,D0 ; Are we closer to fore?
BHS.S @twoColor ; yes => dither
MOVE.B #1, result(A6) ; return true
MOVE.L fGround(A6), A0
LEA realAvg(A6), A1
MOVE.L (A1)+, (A0)+
MOVE.W (A1)+, (A0)+
@twoColor MOVE.L (SP)+, A2
UNLK A6
CLR.L D0
RTD #result-return-4
ENDPROC
;---------------------------------------------------
;
; FUNCTION CheckColors(device:GDHandle,colors:CTabHandle;
; maxTolerance,maxAveTolerance:INTEGER):BOOLEAN; AAA2/24;
;
; See if the list of color specified can be displayed nicely on
; theGDevice.
CheckColors PROC EXPORT
CCVars RECORD {A6Link},DECREMENT
result DS.B 2 ; result: BOOLEAN
device DS.B 4 ; device to check
colors DS.B 4 ; input: color list to check
maxTol DS.B 2 ; maximum tolerance for each color
maxAveTol DS.B 2 ; maximum average tolerance
return DS.B 4 ; return address on stack
A6Link DS.B 4 ; link
oldGD DS.B 4 ; GDevice before we started
;colorCount DS.B 2 ; ctSize+1
aColor DS.B 6 ; scratch rgb
bColor DS.B 6 ; another scratch rgb
hState DS.B 2 ; handle state of clut
linkSize DS.B 0 ; size of record
ENDR
WITH CCVars
LINK A6,#linkSize
MOVEM.L A2-A3/D3-D7,-(SP)
MOVE.L TheGDevice,oldGD(A6)
MOVE.L device(A6),D0 ; did the user specify a GDevice?
BEQ.S @noDevice
MOVE.L D0,TheGDevice
@noDevice
MOVE.B #1,result(A6) ; Assume True
MOVEA.L TheGDevice, A0 ; get a handle to TheGDevice
MOVEA.L (A0), A0 ; dereference the Handle
CMPI.W #$2, gdType(A0) ; check if the device is direct (16 or 32 bits)
BEQ.S @exit
MOVEA.L gdPMap(A0), A0 ; Get the PixMapHandle
MOVEA.L (A0), A0 ; Get the PixMapPtr
MOVEA.L pmTable(A0), A0 ; Get the PixMap CTabHandle
MOVEA.L (A0), A0 ; Get the CTabPtr
MOVE.L ctSeed(A0), D0 ; Get the Seed
MOVEQ #(8+32), D1 ; check for 8-bit grey-scale
CMP.L D0, D1
BEQ.S @exit
MOVE.L colors(A6), A0 ; Get the input color table handle
MOVE.L (A0), A0 ; dereference
MOVE.L ctSeed(A0), D1 ; get the Seed
CMP.L D0, D1 ; check if seeds are identical
BEQ.S @exit
MOVEQ #(4+32), D1 ; check for 4-bit gray-scale destination
CMP.L D0, D1
BEQ.S @exit
; MOVE.W ctSize(A0), D1 ; our device clut is four-bit gray-scale and we're checking that the source clut is four-bits or less
; CMPI.W #15, D1
; BLS.S @exit
;@doneChecking
CLR result(A6) ; default to "false" = failure
CLR.L D7 ; D7 = total color deltas
MOVE.L colors(A6), A0
_HGetState ; A0 already contains the handle to the ColorTable
MOVE D0,hState(A6) ; D6 = previous colors memstate
_HLock
MOVE.L (A0),A2 ; A2->color table to check
MOVE ctSize(A2),D3 ; D3 = last color in table
BEQ.S @goHome
MOVEQ #0, D5 ; initialized number of colors checked
; MOVE D3,D0
; ADDQ #1,D0
; MOVE D0,colorCount(A6) ; save count of colors
; MOVEQ #-1, D6 ; set D6 to impossible value for index check.
ADDQ #8,A2 ; A2->1st color in table
@loop
MOVEQ #4, D0 ; set bit 2 in D0
AND.W (A2), D0 ; test inhibit bit in value field of colorSpec
BNE.S @next ; skip this color if the bit is set
ADDQ.L #1, D5; ; increment number of colors checked
BSR.S @color2color ; Get D5=index, D0=delta, D7 = ·deltas
; CMP.L D6,D5 ; Does it match the last one?
; BEQ.S @gohome ; Yes=>unacceptable
CMP maxTol(A6),D0 ; Are we within maximum tolerance?
BHI.S @goHome ; No=>fail
; MOVE.L D5,D6 ; get last index here
@next ADDQ #8,A2 ; Bump to next color
DBRA D3,@loop ; loop through all colors
TST D5
BEQ.S @goHome
DIVU D5,D7 ; compute average tolerance
; DIVU colorCount(A6),D7 ; compute average tolerance
CMP maxAveTol(A6),D7 ; in range?
BHI.S @goHome ; No=>don't set result true
MOVE.B #1,result(A6) ; We made it through all the colors
@gohome
MOVE.L colors(A6),A0
MOVE hState(A6),D0 ; old handle state
_HSetState
@exit
MOVE.L oldGD(A6),TheGDevice ; restore gdevice
MOVEM.L (SP)+,A2-A3/D3-D7
UNLK A6
CLR.L D0
RTD #result-return-4
@color2color
;convert rgb A2+2 to index in D5, and back to color, delta in D0
SUBQ #4,SP ; space for result
PEA 2(A2)
_Color2Index
; MOVE.L (SP),D5 ; get color's index in D5
PEA aColor(A6) ; place to get actual color
_Index2Color
SUBQ #2,SP
PEA aColor(A6)
PEA 2(A2)
JSR DeltaRGB
CLR.L D0
MOVE (SP)+,D0 ; Get delta into D0
ADD.L D0,D7 ; Sum the delta into D7
RTS
;---------------------------------------------------
;
; PROCEDURE PMgrDispatch(selector:INTEGER); AAA2;
;
; Here, we divvy up our last trap amongst a whole bunch of functions, using D0
; as a selector. All registers preserved during dispatch except D0.
PROC
EXPORT PMgrDispatch
procTable
switch00 DC Entry2Index-procTable ; public choices
switch01 DC Index2Entries-procTable
switch02 DC RestoreDeviceClut-procTable
switch03 DC ResizePalette-procTable
switch04 DC ZapLinks-procTable
switch05 DC WhatPal-procTable
switch06 DC PMgrFinalError-procTable
switch07 DC PMgrFinalError-procTable
switch08 DC PMgrFinalError-procTable
switch09 DC PMgrFinalError-procTable
switch10 DC DeltaRGB-procTable ; secret choices
switch11 DC NewHiliteColor-procTable
switch12 DC PMgrExit-procTable
switch13 DC SaveFore-procTable
switch14 DC SaveBack-procTable
switch15 DC RestoreFore-procTable
switch16 DC RestoreBack-procTable
switch17 DC PMgrFinalError-procTable
switch18 DC ReleaseList-procTable
switch19 DC SetDepth-procTable
switch20 DC HasDepth-procTable
switch21 DC PMgrVersion-procTable
switch22 DC SetPaletteUpdates-procTable
switch23 DC GetPaletteUpdates-procTable
switch24 DC CheckColors-procTable
switch25 DC GetGray-procTable
switchMax EQU (*-procTable)/2
; Say, don't forget that each pmgr dispatch must set D0 to zero on return!
PMgrDispatch
CMP.B #switchMax,D0 ; Is this (yet) a real function?
BHS.S PMgrFinalError ; No! Bye!
MOVE.L A0,-(SP) ; preserve A0
LEA procTable,A0 ; A0->list of proc pointers
AND #$00FF,D0 ; Only use low byte for offset
MOVE (A0,D0*2),D0 ; Get offset to the one we want
ADDA D0,A0 ; Add offset
MOVE.L A0,-(SP) ; Push target as return address
MOVE.L 4(SP),A0 ; Restore A0
RTD #4 ; Go there. Straight.
PMgrFinalError
LSR #8,D0 ; Get to high byte of D0: arg count
MOVE.L (SP)+,A0 ; Pop return address
ADD D0,SP ; Remove those args
MOVEQ #-1,D0 ; Error condition
JMP (A0) ; bye.
ENDPROC
;---------------------------------------------------
; Thus ends the PaletteManager - ah, a sad thing it is, to be done. But WAIT! There's
; MORE! Let's patch RGBFORECOLOR and RGBBACKCOLOR just for grins! Yeah!
IF NOT ROMPaletteMgr THEN ; no patches for the ROM version RWH.C864
IF NOT JacksonPollack THEN ; (skip RGBFore/Back, since JP knows it)
;---------------------------------------------------
;
; procedure RGBForeColor (Color : RGBColor);
;
; This routine takes an RGB triple and sets the current Graf- or CGrafPort
; fields so that drawing will take place with the best match of the
; requested color, using the current GDevice's color matching rules. The
; appropriate fields are set depending on portType
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (RGBForeColor) (RGBForeColor)
RGBForeColor PROC EXPORT
EXPORT RGBBackColor,RGB2OLD
StdDevCall Equ $1D2A0 ; RGBForeColor; RGBBackColor is $4081D2B0 <PB302>
StdDevMask Equ $FFFFFFEF ; the calls are different only at bit 4!
MOVEQ #FGCOLOR,D0 ; get offset to index field
MOVEQ #RGBFgColor,D1 ; get offset to RGB field
SHARE MOVE.L 4(SP),A1 ; point at the RGB color
MOVE.L GRAFGLOBALS(A5),A0 ; get the QuickDraw globals pointer
MOVE.L THEPORT(A0),A0 ; point at the port
PEA 0(A0,D0) ; save pointer to the index field
TST PORTBITS+ROWBYTES(A0) ; is it a new port?
BMI.S NEWPORT ; => yes, set RGB components
JSR RGB2OLD ; else convert RGB to old color
BRA DONE ; =>
; To keep the stack correct we will momentarily preempt A1. We can restore it in a bit.
; Also, since we no longer need the offset to the index field
NewPort Move.L GrafVars(A0),A1 ; get the GrafVars handle
CmpA.L #Nil,A1 ; is it nil?
Beq.S PuntPmCalls ; yes => punt and do the normal call
Move.L (A1),A1 ; dereference it into A1
Move.L 4(SP),D2 ; get the return address
Sub.l ROMBase, D2 ; Make it offset within ROM, <PB302>
And.L #StdDevMask,D2 ; and it with the std mask
Cmp.L #StdDevCall,D2 ; is it from StdDevLoop?
Bne.S NormalCall ; no => make the normal call
Tst.L PmFgColor(A1) ; is there a palette? EHB.PBnnn
Bne.S FoundAPltt ; yes => we can do it AWC.PB508
Tst.L AppPalette ; is there an AppPalette? AWC.PB508
Beq.S NormalCall ; => no, do normal call EHB.PBnnn
FoundAPltt Move PmFlags(A1),D2 ; get the Palette Manager flags AWC.PB508
Cmp #FgColor,D0 ; was it forecolor?
Bne.S GetBack ; no => get back color flag
BTst #PmFgBit,D2 ; did PmForeColor set up this port?
Beq.S PuntPmCalls ; no => continue normally
AddQ #4,SP ; we won't need the pointer to the index
Move pmFgIndex(A1),-(SP) ; push the entry number
_PmForeColor ; set the port using PmForeColor
Bra.S GoHome ; all finished
GetBack BTst #PmBkBit,D2 ; did PmBackColor set up this port?
Beq.S PuntPmCalls ; no => continue normally
AddQ #4,SP ; we won't need the pointer to the index
Move pmBkIndex(A1),-(SP) ; push the entry number
_PmBackColor ; set the port using PmBackColor
Bra.S GoHome ; all through
NormalCall Move PmFlags(A1),D2 ; get flags
Cmp #FgColor,D0 ; is this a foreground call?
Bne.S NotFgCall ; no => clear PmBkBit
BClr #PmFgBit,D2 ; clear the foreground flag bit
Bra.S CommonFlags ; reunite it
NotFgCall BClr #PmBkBit,D2 ; clear the background flag bit
CommonFlags Move D2,PmFlags(A1) ; save the flags to GrafVars
PuntPmCalls Move.L 8(SP),A1 ; restore the pointer to the RGBColor
; Here is the normal RGBForeColor code code
MOVE.L red(A1),red(A0,D1) ; copy red and green components to the port
MOVE.W blue(A1),blue(A0,D1) ; and blue too
; make an rgbColor on the stack
MOVE.L green(A1),-(SP) ; copy green and blue
MOVE.W red(A1),-(SP) ; copy red
SUBQ #4,SP ; make room for function return
PEA 4(SP) ; push pointer to rgb
_Color2Index ; convert it to an index
MOVE.L (SP)+,D0 ; get the index result
ADDQ #6,SP ; get rid of the rgbColor
Done MOVE.L (SP)+,A0 ; get pointer to index field
MOVE.L D0,(A0) ; and set the index field
GoHome Rtd #4 ; all done
RGB2OLD
;-----------------------------------------------
;
; UTILITY TO CONVERT AN RGB (POINTED TO BY A1) VALUE
; TO AN OLD STYLE COLOR VALUE. RETURNS VALUE IN D0. CLOBBERS A0,D1
;
; USES HIGH BIT OF EACH COMPONENT TO SELECT RGB OFF (0) OR ON (1)
MOVEQ #0,D1 ; clear out D1
MOVE (A1)+,D1 ; get red
ADD.L D1,D1 ; get high bit
MOVE (A1)+,D1 ; get green
ADD.L D1,D1 ; get high bit
MOVE (A1)+,D1 ; get blue
ADD.L D1,D1 ; get high bit
SWAP D1 ; get RGB index
noBlue LEA MapTbl,A0 ; get translate table
MOVEQ #0,D0 ; clear out high word
MOVE 0(A0,D1*2),D0 ; convert to planar value
RTS ; => all done
; TABLE TO MAP FROM 3 BIT RGB TO OLD-STYLE COLOR INDICES
MapTBL DC.W blackColor ; RBG = 0,0,0 -> black
DC.W blueColor ; RBG = 0,0,1 -> blue
DC.W greenColor ; RBG = 0,1,0 -> green
DC.W cyanColor ; RBG = 0,1,1 -> cyan
DC.W redColor ; RBG = 1,0,0 -> red
DC.W magentaColor ; RBG = 1,0,1 -> magenta
DC.W yellowColor ; RBG = 1,1,0 -> yellow
DC.W whiteColor ; RBG = 1,1,1 -> white
;---------------------------------------------------
;
; procedure RGBBackColor (Color : RGBColor);
;
; This routine takes an RGB triple and sets the current Graf- or CGrafPort
; fields so that drawing will take place with the best match of the
; requested color, using the current GDevice's color matching rules. The
; appropriate fields are set depending on portType.
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (RGBBackColor) (RGBBackColor)
RGBBackColor
MOVEQ #BKCOLOR,D0 ; get offset to the index field
MOVEQ #RGBBkColor,D1 ; get offset to RGB field
BRA SHARE ; => and use common code
ENDIF ;(Jackson Pollack)
IF PatchGetCTable THEN
;(This GetCTable was copied out of ColorMgr.a, and is used for patching
; when we install the new palette manager without 32-bit quickdraw.)
;---------------------------------------------------
;
; FUNCTION myGetCTable(ID:INTEGER):Handle;
;
; Get a 'clut' resource of the specified ID, as a non-resource
; handle. Unless, of course, the number is 32+[1,2,4,8] in which
; case we return a gray scale of that size. Or if the number is
; 64+[1,2,4,8] we'll return a clut with a hilite modification.
;
; Passing 64 plus other than 1, 2, 4, or 8 will yield strange results.
;
; stack like this: (SP) return.L, 4(SP) depth.W, 6(SP) result handle.L
;
; <dvb8> for whole routine
PROC
EXPORT MyGetCTable
GrayMuls DC.W $FFFF,$5555,$0000,$1111,$0000,$0000,$0000,$0101 ; <BAL 06Jun89>
; gray multiplier 1-bit 2-bit 4-bit 8-bit
doGrayClut AND #$F,D0 ; Mask the graybit
MOVE D0,4(SP) ; Put it in the passed param
CLR.L D1
ADDQ #3,D0 ; + 3 becomes * 8 on next line, for c-Spec size
BSET D0,D1 ; 2 to the nth
ADDQ.L #8,D1 ; Add size of ctab header
MOVE.L D1,D0 ; Here, for newhandle
_NewHandle ; Get a brand new colortable
BEQ.S @gotGrayH ; Did we?
CLR.L 6(SP) ; No=>return nil
RTD #2
@gotGrayH MOVE 4(SP),D0 ; Get depth again
LEA GrayMuls-2,A1 ; A1->our gray multiplier table <2.1>
MOVE.w (A1,D0*2),D1 ; D1.w = color step for this bit depth <BAL 06Jun89>
move.w d1,d2 ; copy into d2 <BAL 06Jun89>
swap d2 ; set up high word <BAL 06Jun89>
move.w d1,d2 ; replicate throughout long <BAL 06Jun89>
MOVE.L (A0),A1 ; A1->our brand new ctable clut
move.w #$8000,transIndex(A1) ; mark as device clut
CLR D1 ; From bit depth,
BSET D0,D1 ; Generate number of entries
SUBQ #1,D1 ; Minus one, for ctSize silliness
MOVE D1,ctSize(A1) ; Set size of colortable
CMPI #3,D0 ; Size 1 or 2 bits? <dvb>
BLT.S @graySeed ; Yes => don't call it GrayScale by seed <dvb>
ADD #32,D0 ; Constant +32 for GrayScale seeds
@graySeed MOVE.L D0,ctSeed(A1) ; Jam seed <dvb>
LEA ctTable(A1),A1 ; A1->first colorSpec
MOVEQ #-1,D0 ; Lowest index is white
MOVEQ #0,D1 ; D1 will be .value fields <dvb>
@grayLoop MOVE D1,(A1)+ ; put pixel value in .value field <dvb>
ADDQ #1,D1 ; <dvb>
MOVE.L D0,(A1)+ ; Stash red and green
MOVE D0,(A1)+ ; Stash blue, A1->next cSpec
SUB.L D2,D0 ; Bump D0 to next reasonable value
BCC.S @grayLoop ; Until we go under zero, beyond black
BRA GoHome
doHiliteClut AND #$F,D0 ; Mask the hilitebit
MOVE D0,-(SP) ; Push it for the Resource read
BSR ReadIt ; Okay, read it.
MOVE.L A0,D0 ; A good thing?
BEQ GoHome ; No=>go home (with NIL from A0)
MOVE.L (A0),A1 ; A1->color table
SUBQ #4,SP ; Space for new seed
_GetCTSeed ; Get that new seed
MOVE.L (SP)+,ctSeed(A1) ; Put seed into synthetic table
MOVE 4(SP),D0 ; D0 = clutID again
BTST #1,D0 ; Two bit mode?
BEQ.S checkFour ; No=>check other stuff
; If the hilite color is a gray then CLUT is OK <2.2>
LEA HiliteRGB,A1 ; Point at hilite color <2.2>
MOVE.B red(A1),D1 ; Get red msb <2.2>
CMP.B green(A1),D1 ; green same as red? <2.2>
BNE.S @notGray ; no, go use it. <2.2>
CMP.B blue(A1),D1 ; blue same as red and green? <2.2>
BEQ GoHome ; yes, leave clut alone. <2.2>
@notGray MOVE.L (A0),A1 ; A1->color table <2.2>
LEA ctTable+8+rgb(A1),A1 ; Bump A1 to 2nd entry.rgb.red
MOVE.L #$7FFF7FFF,(A1)+ ; Put 50% gray into red,green
MOVE #$7FFF,(A1)+ ; and blue
ADDQ #2,A1 ; Bump past .value field in third entry
MOVE.L HiliteRGB,(A1)+ ; Put hilite color into red,green
MOVE HiliteRGB+blue,(A1) ; and blue.
BRA GoHome
checkFour BTST #2,D0 ; Four bit mode?
BEQ GoHome ; No => must be 1 or 8-bit, so we're done.
MOVE #14,D2 ; DBRA counter, skipping white
MOVE.L #$0001FFFF,D1 ; Lo word = error distance, Hi word = best index
@B4loop SUBQ #2,SP ; space for result
PEA HiliteRGB ; push system hilite color
PEA ctTable+rgb(A1,D2*8) ; push color we're checking
JSR DeltaRGB
MOVE (SP)+,D0
CMP D0,D1
BLS.S @B4loopEnd
MOVE D0,D1 ; Get new smallest delta
SWAP D1 ; D1 = Get index number in low word
MOVE D2,D1 ; Get new closest index
SWAP D1 ; D1 = Put delta back to low word
@B4loopEnd SUBQ #1,D2
BNE.S @B4loop ; Loop on down, but skip zero
CMPI #$3000,D1 ; Are we pretty darned tolerant?
BLS.S GoHome ; Yes=> we're fine, go home
SWAP D1
LEA ctTable+rgb+red(A1,D1*8),A1 ; A1->RGB to tweak
@realClose MOVE.L HiliteRGB+red,D0 ; D0 = hilite r,g
SWAP D0 ; D0.W = red
ADD red(A1),D0 ; D0.W = hilite red+old red
ROXR #1,D0 ; Average
MOVE D0,red(A1) ; write red
SWAP D0
ADD green(A1),D0 ; D0.W = hilite green+old green
ROXR #1,D0 ; Average
MOVE D0,green(A1) ; write green
MOVE HiliteRGB+blue,D0 ; D0.W = hilite blue
ADD blue(A1),D0
ROXR #1,D0 ; Average
MOVE D0,blue(A1) ; write blue
SUBQ #2,SP ; space for result
PEA HiliteRGB ; Have we really got the hilite
PEA (A1) ; color within a reasonable range?
JSR DeltaRGB ; Let's see.
CMPI #$3000,(SP)+ ; 3000 is good enough to look decent.
BHI.S @realClose ; But, its not there yet, so avg again.
BRA.S GoHome
myGetCTable MOVE 4(SP),-(SP) ; First, try to read a resource
BSR.S ReadIt ; (do that)
MOVE.L A0,D0 ; Get anything?
BEQ.S notRes ; No=>try other means
GoHome MOVE.L A0,6(SP) ; Yes=>stash it
RTD2 RTD #2 ; roger and out.
notRes MOVE 4(SP),D0 ; Get requested ID
CMPI #72,D0 ; 72 is the highest we can noodle
BHI.S RTD2
MOVE.L #$00000116,D1 ; Bits 1, 2, 4, and 8 are set
BTST D0,D1 ; Are low 5 bits in [1,2,4,8]?
BEQ.S RTD2
BTST #5,D0
BNE.S doGrayClut ; 32+[1,2,4,8]
BTST #6,D0
BNE.S doHiliteClut ; 64+[1,2,4,8]
BRA.S RTD2
readIt SUBQ #4,A7 ; space for result
MOVE.L #'clut',-(SP) ; resource type
MOVE 12(SP),-(SP) ; push ID number
_GetResource ; Get it.
MOVE.L (A7)+,D0 ; D0 = resource handle.
BEQ.S @tryROM ; (OR NOT!) maybe the ROM has it.
MOVE.L D0,-(SP) ; Push to save it, a moment.
MOVE.L D0,-(SP) ; Push to detach it
_DetachResource ; It's no longer a resource
MOVE.L (SP)+,A0 ; We'll return it in A0.
_HNoPurge ; make this non-purgeable (if it was) <16May89> DAF
MOVE.L (A0),A1 ; But first,
SUBQ #4,SP ; Number one,
_GetCTSeed ; Since we don't know where its been
MOVE.L (SP)+,(A1) ; A Fresh seed.
BRA.S @doneRead ; return, sans ID
@tryROM MOVE #-1,RomMapInsert ; This time, try 'da ROM
SUBQ #4,SP ; result
MOVE.L #'clut',-(SP) ; resource type
MOVE 12(SP),-(SP) ; resource ID
_GetResource ; Get it.
MOVE.L (A7)+,D0
BEQ.S @readFail ; It wasn't there! Not at all!
MOVE.L D0,A0 ; Put here for hand to hand
_HandToHand ; Make a normal handle from ROM resource
BEQ.S @doneRead ; Made it? If so, return, sans ID
@readFail SUBA.L A0,A0 ; A miserable failure.
@doneRead RTD #2 ; Lose ID, and go home.
ENDIF
IF PatchInitGDevice THEN
;=========================================================================================
;=========================================================================================
;
; Patch to InitGDevice. Add support for GDevices with baseAddrs that change across
; depths (Trident card) in a MultiFinder friendly way.
;
;=========================================================================================
;=========================================================================================
myInitGDevice PROC EXPORT
iiROMGetDevPixMap EQU $18FC0
WITH VDPageInfo ;<1.1>
;-------------------------------------------------------------
;
; PROCEDURE InitGDevice (refNum: INTEGER; mode: LONGINT; GDH: GDHandle);
;
; Initialize the specified device to the specified mode. The GDevice
; data is placed into the provided handle.
;
; If mode = -1 then the driver is not called. It is assumed that the pixmap
; has been set up before InitGDevice is called.
;
; CAUTION: this routine is used during ROM boot; various Macintosh functions
; may not yet be available! <dvb - found out the hard way>
;
IGDVars RECORD {A6Link},DECREMENT
result DS.B 0 ; no result
REFNUM DS.B 2
MODE DS.B 4 ; LONG, mode for video card
GDH DS.B 4 ; LONG, handle to devPort
return DS.B 4 ; the return address
A6Link DS.B 4 ; our link
IOPBlk DS.B IOVQElSize ; [64] parameter blk for I/O calls
VidParms DS.B 12 ; [12] size of mode params
GDHState DS.B 2 ; [word] lock state of GDH
GDPState DS.B 2 ; [word] lock state of GDP
SaveDevice DS.B 4 ; [long] saved device handle
oldBaseAddr DS.B 4 ; old base address, for later comparison
oldPort DS.B 4 ; thePort, before we got here
oldColor DS.B 8 ; a colorSpec used to reinstantiate fg/bk
VARSIZE DS.B 0 ; size of locals
ENDR
WITH IGDVars
LINK A6,#VARSIZE ; allocate stack frame
MOVEM.L D3/A2-A4,-(SP) ; save off work registers
MOVE.L GDH(A6),A0 ; get the gDevice handle
_HGetState ; get the current lock state
MOVE D0,GDHState(A6) ; save the state
_HLOCK ; and lock down the gDevice
MOVE.L (A0),A2 ; get pointer to gDevice record
MOVE.L GDPMap(A2),A0 ; get handle to pixMap
MOVE.L (A0),A1 ; A1->pixmap
MOVE.L baseAddr(A1),oldBaseAddr(A6) ; save the base address, for later portfixing
_HGetState ; get the current lock state of the pixmap
MOVE D0,GDPState(A6) ; save the state
_HLOCK ; lock it down
MOVE.L (A0),A3 ; keep pointer in A3
MOVE.L theGDevice,SaveDevice(A6) ; save theGDevice
TST.B QDExist ; qd around?
BNE.S @noShield ; no, don't shield cursor
BTST #screenDevice,gdFlags(A2) ; is it screen (check hi byte with #>8)
BEQ.S @noShield
PEA gdRect(A2)
CLR.L -(SP) ; in global cošrds
_ShieldCursor
@noShield
; initialize the GDevice's mode and refnum
MOVE REFNUM(A6),GDRefNum(A2) ; set up RefNum
MOVE.L MODE(A6),D0 ; get the mode
CMP.L MinusOne,D0 ; is the mode -1?
BEQ ModeOK ; if so, then don't call the driver
; set up the driver parameter block in case we need to use it
LEA IOPBlk(A6),A0 ; point to parameter block
CLR.L ioCompletion(A0) ; no completion routine
CLR.W ioVRefNum(A0) ; no volRefNum
MOVE RefNum(A6),ioRefNum(A0) ; set device's refnum
LEA VidParms(A6),A1 ; point to params for GetMode
MOVE.L A1,csParam(A0) ; point to param list
CMP.L GDMode(A2),D0 ; has the mode changed?
BEQ GrayOrColor ; => no, so don't set depth
MOVE.L D0,GDMode(A2) ; set up mode
; setup the gDevice fields for the new screen depth
CLR GDCCDepth(A2) ; invalidate cursor depth <C837>
MOVEM.L A0/A1,-(SP) ; save these regs
MOVE REFNUM(A6),-(SP) ; push refnum
MOVE.L MODE(A6),-(SP) ; push mode
MOVE.L GDPMap(A2),-(SP) ; pixMap handle
PEA GDType(A2) ; point to device type
jsrROM iiROMGetDevPixMap ; read in pixMap from device
MOVEM.L (SP)+,A0/A1 ; restore them
; first, set the mode (A0 points to IOPB, A1 to control parameter block)
MOVE #2,csCode(A0) ; csc_GetMode
MOVE.L mode(A6),D0 ; get the mode
MOVE D0,csMode(A1) ; set desired mode
CLR csPage(A1) ; set page 1
CLR.L csData(A1) ; no additional data
_Control ,IMMED ; SetMode(Mode,Page,Data);
; then gray the screen
MOVE #5,csCode(A0) ; csc_GrayPage
_Control ,IMMED ; paint current page gray
; set the device to color or monochrome, according to GDFlags
GrayOrColor
MOVE GDFlags(A2),D0 ; get flags word
NOT D0 ; flip all bits
AND #1,D0 ; clear all but low bit
MOVE.B D0,csMode(A1) ; csMode = color/gray scale
MOVE #6,csCode(A0) ; csc_SetGray
_Control ,IMMED ; set color or monochrome
; if the device has a color table, set the device's color table
CMP #ClutType,GDType(A2) ; is there a lookup table?
BNE.S NoTbl ; =>no, don't set one
MOVE.L pmTable(A3),A0 ; get handle to color table
_HLock ; lock down the color table
;+++ LEA VidParms(A6),A1 ; point to params for SetEntries
MOVE.L (A0),A0 ; get ctabPtr <DAF>
CLR.W csStart(A1) ; start at zero, use sequence mode <DAF>
MOVE.W ctSize(A0),csCount(A1) ; for the length of the table <DAF>
LEA ctTable(A0),A0 ; get pointer to colorspecs <DAF>
MOVE.L A0,csTable(A1) ; color table pointer is first param <DAF>
LEA IOPBlk(A6),A0 ; point to parameter block
MOVE.W #3,csCode(A0) ; csc_SetEntries
MOVE.L A1,csParam(A0) ; move addr of parms into block
_Control ,IMMED ; SetEntries(ColorTable);
MOVE.L pmTable(A3),A0 ; get handle to color table
_HUnlock ; unlock the color table
NoTbl
; if CLUT or fixed color table, build inverse table
CMP #DirectType,GDType(A2) ; should there be an inverse table?
BEQ.S ModeOK ; =>no inverse table
MOVE.L pmTable(A3),-(SP) ; push color table handle
MOVE.L GDITable(A2),-(SP) ; push inverse table handle
MOVEQ #4,D0 ; make 4-4-4 inverse tables
MOVE D0,GDResPref(A2) ; save in GDevice
MOVE D0,-(SP) ; and push res
_MakeITable ; and generate table
; If this device has not been initialized from the system file, then copy the
; bounds from the pixMap to the GDRect. Otherwise copy the GDRect to the Bounds.
ModeOK
LEA BOUNDS(A3),A0 ; point to pixmap.bounds <C837>
LEA GDRECT(A2),A1 ; point to device's global rect
MOVE GDFlags(A2),D0 ; get the flags word
BTST #RAMInit,D0 ; initialized from RAM?
BEQ.S BndsOK ; => no, copy pixMap.bounds to GDRect
EXG A0,A1 ; else copy GDRect to pixMap.bounds
BndsOK MOVE.L (A0)+,(A1)+ ; copy topLeft
MOVE.L (A0)+,(A1)+ ; copy botRight
; <dvb 3Jan89>
; if we're about the main device, then fix all those
; potentially errant ports.
;
TST.B QDExist ; (Unless QuickDraw don't exist)
BNE @noQD
MOVE.L portList,D1 ; or if portlist = 0 or -1
BEQ @noQD
ADDQ.L #1,D1
BEQ @noQD
BTST #mainScreen,D0 ; is it the main scrn? (flags already in D0)
BEQ @notMain
PEA oldPort(A6) ; Save the current port
_GetPort
MOVE.L mainDevice,theGDevice ; and set to the screen
MOVE.L PortList,A4 ; A4 = handle to list of ALL ports
MOVE.L (A4),A4 ; A4->list of all ports
MOVE (A4),D3 ; D3 = number of ports that exist
BRA @portWalkEnd
@portWalkLoop
MOVE.L PortList,A4
MOVE.L (A4),A4
MOVE.L 2(A4,D3.W*4),A4 ; A4 = this port
MOVE.L A4,-(SP) ; Set to each port in the port list
_SetPort
MOVE.L oldBaseAddr(A6),D1 ; D1 = the scrnbase of ports to change
BTST #7,portVersion(A4) ; high bit set?
BEQ.S @oldPort
MOVE.L portPixMap(A4),A4 ; A4 = handle to the port's pixmap
MOVE.L (A4),A4 ; A4->port's pixmap
CMP.L baseAddr(A4),D1 ; same as the screen's?
BNE.S @portWalkEnd ; no, skip this port
MOVE.L baseAddr(A3),baseAddr(A4) ; replace a bunch of fields
MOVE rowBytes(A3),rowBytes(A4)
MOVE.L pixelType(A3),pixelType(A4) ; (gets pixelSize, too)
MOVE.L cmpCount(A3),cmpCount(A4) ; (gets cmpSize, too)
MOVE.L planeBytes(A3),planeBytes(A4)
PEA oldColor(A6) ; placeholder for reinstantiating colors
MOVE.L (SP),-(SP)
MOVE.L (SP),-(SP)
MOVE.L (SP),-(SP)
_SaveFore ; Save and restore the foreground color
_RestoreFore ; (Allowing for pmFore)
_SaveBack ; And the same for the background
_RestoreBack
BRA.S @portWalkEnd
@oldPort
CMP.L portBits+baseAddr(A4),D1 ; same base on old port?
BNE.S @portWalkEnd
MOVE.L baseAddr(A3),portBits+baseAddr(A4)
MOVE rowBytes(A3),D1
AND #nurbMask,D1 ; handle NURBs here
MOVE D1,portBits+rowBytes(A4)
@portWalkEnd
DBRA D3,@portWalkLoop
MOVE.L oldPort(A6),-(SP) ; restore the pre-existing port
_SetPort
MOVE.L oldBaseAddr(A6),D1
CMP.L scrnBase,D1 ; fix scrnBase too, if neede
BNE.S @notMain
MOVE.L baseAddr(A3),scrnBase
@notMain
_AllocCursor
_ShowCursor
@noQD
;
; notify the Palette Manager that the mode has changed
;
; <2.6> moved after GDRect has been adjusted <2.6>
CMP.L #-1,PMgrHandle ; has the Palette Mgr been initialized?
BEQ.S @noPMgr ; nope, so skip this
MOVE.L GDH(A6),-(SP) ; push the device handle
_RestoreDeviceClut ; call the Palette Manager Unhook device vector
@noPMgr
MOVE.L SaveDevice(A6),theGDevice ; restore theGDevice
MOVE.L GDPMap(A2),A0 ; get pixMap handle
MOVE GDPState(A6),D0 ; get the lock state
_HSetState ; restore prior state
MOVE.L GDH(A6),A0 ; get the gDevice handle
MOVE GDHState(A6),D0 ; get the lock state
_HSetState ; restore prior state
MOVEM.L (SP)+,D3/A2-A4 ; restore work registers
UNLINK result-return-4,'INITGDEV'
ENDPROC
ENDIF
;---------------------------------------------------
;
; procedure myInitMenus;
;
; This code patches InitMenus. It would be better to call InitPalettes from InitWindows
; but MultiFinder has that patched out and we would again have to duplicate our efforts.
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (InitMenus) (myInitMenus)
myInitMenus PROC EXPORT
ROMInitMenus Equ $109EE ; AWC.PB506
JsrRom ROMInitMenus ; call InitMenus AWC.PB506
_InitPalettes ; set up the AppPalette AWC.PB520
Rts ; go home AWC.PB520
;---------------------------------------------------
;
; procedure myNewCWindow()
;
; Initialize the palette manager fields of the new window.
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (NewCWindow) (myNewCWindow)
myNewCWindow PROC EXPORT
ROMNewCWindow EQU $0F9F6 ; normal NewCWindow routine <PB302>
; shuffle parameters so it will return to us
MOVE.L SP,A0 ; get src for params
MOVE.L SP,A1 ; get dst for params
MOVE.L (A0)+,D1 ; save RTS
MOVEQ #7,D0 ; move 8 longs
@NxtLong MOVE.L (A0)+,(A1)+ ; move a long
DBRA D0,@NxtLong ; repeat for all longs
MOVE.L D1,30(SP) ; stuff original RTS
JSRROM ROMNewCWindow ; call NewCWindow <PB302>
; always set the default palette to 0
MOVE.L (SP),A1 ; get the window
MOVE.L GrafVars(A1),A0 ; get handle to vars
MOVE.L (A0),A0 ; point to vars
CLR.L PMFgColor(A0) ; and clear palette
MOVE.L (SP)+,A1 ; get window pointer
MOVE.L (SP),A0 ; get return address
MOVE.L A1,(SP) ; stuff wPtr
JMP (A0) ; and return
;---------------------------------------------------
;
; procedure myNewWindow();
;
; When NewWindow is called, do an ActivatePalette in case there's a default palette.
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (NewWindow) (myNewWindow)
myNewWindow PROC EXPORT
ROMNewWindow EQU $0FA08 ; normal NewWindow routine <PB302>
; shuffle parameters so it will return to us
MOVE.L SP,A0 ; get src for params
MOVE.L SP,A1 ; get dst for params
MOVE.L (A0)+,D1 ; save RTS
MOVEQ #7,D0 ; move 8 longs
@NxtLong MOVE.L (A0)+,(A1)+ ; move a long
DBRA D0,@NxtLong ; repeat for all longs
MOVE.L D1,30(SP) ; stuff original RTS
JSRROM ROMNewWindow ; call NewWindow <PB302>
MOVE.L (SP),-(SP) ; push the window
_ActivatePalette ; and activate the system palette
@DONE MOVE.L (SP)+,A1 ; get window pointer
MOVE.L (SP),A0 ; get return address
MOVE.L A1,(SP) ; stuff wPtr
JMP (A0) ; and return
;---------------------------------------------------
;
; procedure HiliteWindow();
;
; Patch HiliteWindow to call ActivatePalette if called from SelectWindow
; AND if it is not called from MoveWindow!
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (HiliteWindow) (myHiliteWindow)
myHiliteWindow PROC EXPORT
FromSelect EQU $1016A ; RTS if called from select <PB302>
FromMove EQU $10396 ; RTS if selected from Move <PB302>
ROMHilite EQU $0FFCE ; real HiliteWindow <PB302>
CMPRA FromSelect,(SP) ; from selectWindow? <PB302>
BNE.S @JustHilite ; => no, just hilite
CMPRA FromMove,$38(SP) ; from Move? <PB302>
BEQ.S @JustHilite ; => yes, just hilite
TST.B 4(SP) ; hiliting?
BEQ.S @JustHilite ; => no, just (un)hilite
LEA 6(SP),A0 ; point to window
MOVE.L (A0),-(SP) ; push window
MOVE -(A0),-(SP) ; push boolean
JSRROM ROMHilite ; call hilite in ROM <PB302>
MOVE.L 6(SP),-(SP) ; push window pointer
_ActivatePalette ; and activate its palette
RTD #6 ; strip 6 bytes params and return
@JustHilite JMPROM ROMHilite ; and complete the call <PB302>
;---------------------------------------------------
;
; procedure MyMoveWindow
;
; Patch MoveWindow to call ActivatePalette
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (MoveWindow) (myMoveWindow)
MyMoveWindow PROC EXPORT
ROMMove EQU $0FD9C ; real MoveWindow <PB302>
LEA 10(SP),A0 ; point to window
MOVE.L (A0),-(SP) ; push window
MOVE.L -(A0),-(SP) ; push dst location
MOVE -(A0),-(SP) ; push frontflag
JSRROM ROMMove ; call movewindow <PB302>
MOVE.L 10(SP),-(SP) ; push window
_ActivatePalette ; and activate its palette
RTD #10 ; strip 10 bytes and return
;---------------------------------------------------
;
; procedure MySizeWindow
;
; Patch SizeWindow to call MySetPalette
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (SizeWindow) (mySizeWindow)
MySizeWindow PROC EXPORT
ROMSize EQU $1000E ; real SizeWindow <PB302>
LEA 10(SP),A0 ; point to window
MOVE.L (A0),-(SP) ; push window
MOVE.L -(A0),-(SP) ; push dst location
MOVE -(A0),-(SP) ; push frontflag
JSRROM ROMSize ; call SizeWindow <PB302>
MOVE.L 10(SP),-(SP) ; push window
_ActivatePalette ; and activate its palette
RTD #10 ; strip 10 bytes and return
;---------------------------------------------------
;
; procedure MyClose
;
; Patch CloseWindow to call DisposPalette. In the initial system disk release, this
; patch mistakenly operated on DisposeWindow instead of CloseWindow.
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (CloseWindow) (myClose)
MyClose PROC EXPORT
ROMClose EQU $0FB6E ; real CloseWindow <PB302>
MOVE.L 4(SP),A0 ; get the window
TST PORTBITS+ROWBYTES(A0) ; is it new?
BPL.S @NotNew ; => no
MOVE.L GrafVars(A0),A0 ; get grafVar handle
MOVE.L (A0),A0 ; point at grafVars
MOVE.L PmFgColor(A0),D0 ; is there a palette
BEQ.S @NotNew ; => no
Move.L D0,A0 ; let's use an address register AWC.PB457
Move.L (A0),A0 ; dereference it AWC.PB457
BTst #DisposeBit,pmPrivate(A0) ; should we dispose of it? AWC.PB457
Beq.S @NotNew ; no => the user has to dispose of it AWC.PB457
MOVE.L D0,-(SP) ; else push palette
_DisposePalette ; and dump it
@NotNew JMPROM ROMClose ; and dispose the window <PB302>
;---------------------------------------------------
;
; procedure MyShowHide(WindowPtr; BOOLEAN);
;
; Patch MyShowHide to call ActivatePalette. If it is being called to show a hidden window,
; then do the ActivatePalette.
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (ShowHide) (myShowHide)
MyShowHide PROC EXPORT
ROMShow EQU $0F742 ; real ShowHide <PB302>
LEA 6(SP),A0 ; point to window
MOVE.L (A0),-(SP) ; push window
MOVE -(A0),-(SP) ; push boolean
JSRROM ROMShow ; call showhide <PB302>
MOVE.L A1,-(SP) ; save A1 for ShowHide!
MOVE.L 10(SP),-(SP) ; push window
_ActivatePalette ; and activate its palette
MOVE.L (SP)+,A1 ; restore A1 for ShawHide
RTD #6 ; strip 10 bytes and return
;---------------------------------------------------
;
; procedure MyExit;
;
; Patch MyExit to call DisposePalette for all palettes in the app heap. In addition, jam
; theGDevice and srcDevice with MainDevice. As if that weren't enough, make sure that
; cursor interrupts are enabled.
;
; This patch is not installed by A/UX or under MultiFinder.
;
; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (MyExit) (myExit)
MyExit PROC EXPORT
EXPORT myExitExit ; address of JMP target to daisy chain <PB158>
ROMIAZInit EQU $4080DEF8 ; jump back into ROM
ROMAppZoneAddr EQU $4080D434 ; a useful routine
MOVEM.L A0-A6/D0-D4,-(SP) ; save all registers
_PMgrExit
MOVE.L MainDevice,A0 ; get the main device
MOVE.L A0,SrcDevice ; set the src device
MOVE.L A0,theGDevice ; and the current device
MOVE #$2000,SR ; make sure interrupts enabled
MOVEM.L (SP)+,A0-A6/D0-D4 ; restore all registers
JMP $4080000A ; jump to next code in chain <PB158>
myExitExit EQU *-4 ; address of JMP target <PB158>
ENDIF
; Okay, that's it. We're out of here!