
		*** ColorPatch ***

		INCDIR	Include:
		INCLUDE exec/exec_lib.i
		INCLUDE exec/memory.i
		INCLUDE exec/lists.i
		INCLUDE	graphics/view.i
		INCLUDE	graphics/graphics_lib.i
		INCLUDE intuition/screens.i
		INCLUDE intuition/intuition_lib.i
		INCLUDE dos/dos_lib.i


DEBUG		EQU	0

		IFNE	DEBUG
		OPT	L-,D+
		ELSE
		OPT	L+,D-
		ENDC

		*** Knoten-Struktur ***

		STRUCTURE kn_Node,MLN_SIZE
		APTR	kn_ViewPort
		APTR	kn_AltCMap
		APTR	kn_RGBBuf
		LABEL	kn_Size


		*** Debugging Code ***

		IFNE	DEBUG

		move.l	4.w,a6
		lea	DosName(pc),a1
		moveq	#0,d0
		jsr	_LVOOpenLibrary(a6)
		move.l	d0,_DOSBase
		lea	GfxName(pc),a1
		moveq	#0,d0
		jsr	_LVOOpenLibrary(a6)
		move.l	d0,_GfxBase
		lea	IntName(pc),a1
		moveq	#0,d0
		jsr	_LVOOpenLibrary(a6)
		move.l	d0,_IntuitionBase

		move.l	_IntuitionBase,a6
		sub.l	a0,a0
		lea	TagList(pc),a1
		jsr	_LVOOpenScreenTagList(a6)
		move.l	d0,_Screen
		beq	skip

		moveq	#0,d7
felder		move.l	d7,d0
		move.l	_Screen,a1
		lea	sc_RastPort(a1),a1
		move.l	_GfxBase,a6
		jsr	_LVOSetAPen(a6)
		move.l	d7,d0
		mulu	#32,d0
		move.w	#100,d1
		move.l	d0,d2
		add.w	#30,d2
		move.l	d1,d3
		add.w	#30,d3
		move.l	_Screen,a1
		lea	sc_RastPort(a1),a1
		move.l	_GfxBase,a6
		jsr	_LVORectFill(a6)
		addq.l	#1,d7
		cmp.l	#8,d7
		bne.s	felder

		move.l	_GfxBase,a6
		move.l	_LVOLoadRGB32+2(a6),OldLoadRGB32
		move.l	_LVOSetRGB32CM+2(a6),OldSetRGB32CM
		move.l	_LVOLoadRGB4+2(a6),OldLoadRGB4
		move.l	_LVOMakeVPort+2(a6),OldMakeVPort
		move.l	_LVOLoadView+2(a6),OldLoadView

		bsr	_InstallPatch

		move.l	_DOSBase(pc),a6
		moveq	#100,d1
		jsr	_LVODelay(a6)

debug		move.l	_GfxBase,a6
		move.l	_Screen,a0
		lea	sc_ViewPort(a0),a0
		lea	Table(pc),a1
		bsr	NewLoadRGB32

		move.l	_DOSBase(pc),a6
		moveq	#100,d1
		jsr	_LVODelay(a6)

		bsr	_RemovePatch

		move.l	_IntuitionBase,a6
		move.l	_Screen,a0
		jsr	_LVOCloseScreen(a6)

skip		move.l	4.w,a6
		move.l	_IntuitionBase,a1
		jsr	_LVOCloseLibrary(a6)
		move.l	_GfxBase,a1
		jsr	_LVOCloseLibrary(a6)
		move.l	_DOSBase,a1
		jsr	_LVOCloseLibrary(a6)
		rts

_DOSBase	dc.l	0
_GfxBase	dc.l	0
_IntuitionBase	dc.l	0
_Screen		dc.l	0

DosName		dc.b	"dos.library",0
GfxName		dc.b	"graphics.library",0
IntName		dc.b	"intuition.library",0

TagList		dc.l	SA_Width,320
		dc.l	SA_Height,256
		dc.l	SA_Depth,3
		dc.l	SA_DisplayID,LORES_KEY
		dc.l	TAG_END

Table		dc.w	2
		dc.w	0
		dc.l	$7FFFFFFF,$7FFFFFFF,$7FFFFFFF
		dc.l	$FFFFFFFF,$00000000,$00000000
		dc.w	2
		dc.w	4
		dc.l	$00000000,$FFFFFFFF,$00000000
		dc.l	$00000000,$00000000,$FFFFFFFF
		dc.w	0


		ENDC

		; *** Install the patch ***

		XDEF	_InstallPatch

_InstallPatch	move.l	a6,-(sp)

		tst.w	Patched
		bne	ip_Okay

		lea	Knotenliste(pc),a0
		NEWLIST	a0

		bsr	CalcCorrTab

		IFEQ	DEBUG

		move.l	4.w,a6

		move.l	_GfxBase,a1
		move.w	#_LVOLoadRGB32,a0
		move.l	#NewLoadRGB32,d0
		jsr	_LVOSetFunction(a6)
		move.l	d0,OldLoadRGB32

		move.l	_GfxBase,a1
		move.w	#_LVOSetRGB32CM,a0
		move.l	#NewSetRGB32CM,d0
		jsr	_LVOSetFunction(a6)
		move.l	d0,OldSetRGB32CM

		move.l	_GfxBase,a1
		move.w	#_LVOLoadRGB4,a0
		move.l	#NewLoadRGB4,d0
		jsr	_LVOSetFunction(a6)
		move.l	d0,OldLoadRGB4

		move.l	_GfxBase,a1
		move.w	#_LVOMakeVPort,a0
		move.l	#NewMakeVPort,d0
		jsr	_LVOSetFunction(a6)
		move.l	d0,OldMakeVPort

		move.l	_GfxBase,a1
		move.w	#_LVOLoadView,a0
		move.l	#NewLoadView,d0
		jsr	_LVOSetFunction(a6)
		move.l	d0,OldLoadView

		ENDC

		move.w	#-1,Patched

ip_Okay		moveq	#0,d0
		move.l	(sp)+,a6
		rts



		; *** Remove the patch ***
		;
		; ->d0=Success (0=OK,-1=Failure)

		XDEF	_RemovePatch

_RemovePatch	move.l	a6,-(sp)

		tst.w	Patched
		beq	rp_Okay

		IFEQ	DEBUG

		move.l	4.w,a6
		jsr	_LVOForbid(a6)

		move.l	_GfxBase,a1
		move.w	#_LVOLoadRGB32,a0
		move.l	OldLoadRGB32,d0
		jsr	_LVOSetFunction(a6)
		cmp.l	#NewLoadRGB32,d0
		bne	rp_failed1

		move.l	_GfxBase,a1
		move.w	#_LVOSetRGB32CM,a0
		move.l	OldSetRGB32CM,d0
		jsr	_LVOSetFunction(a6)
		cmp.l	#NewSetRGB32CM,d0
		bne	rp_failed2

		move.l	_GfxBase,a1
		move.w	#_LVOLoadRGB4,a0
		move.l	OldLoadRGB4,d0
		jsr	_LVOSetFunction(a6)
		cmp.l	#NewLoadRGB4,d0
		bne.s	rp_failed3

		move.l	_GfxBase,a1
		move.w	#_LVOMakeVPort,a0
		move.l	OldMakeVPort,d0
		jsr	_LVOSetFunction(a6)
		cmp.l	#NewMakeVPort,d0
		bne.s	rp_failed4

		move.l	_GfxBase,a1
		move.w	#_LVOLoadView,a0
		move.l	OldLoadView,d0
		jsr	_LVOSetFunction(a6)
		cmp.l	#NewLoadView,d0
		bne.s	rp_failed5

		jsr	_LVOPermit(a6)

		ENDC

		clr.w	Patched
		bsr	_MaintKnoten

rp_Okay		moveq	#0,d0
rp_Finished	move.l	(sp)+,a6
		rts

		IFEQ	DEBUG

		; undo changes if unpatching failed

rp_failed5	move.l	_GfxBase,a1
		move.w	#_LVOLoadView,a0
		move.l	#NewLoadView,d0
		jsr	_LVOSetFunction(a6)

rp_failed4	move.l	_GfxBase,a1
		move.w	#_LVOMakeVPort,a0
		move.l	#NewMakeVPort,d0
		jsr	_LVOSetFunction(a6)

rp_failed3	move.l	_GfxBase,a1
		move.w	#_LVOLoadRGB4,a0
		move.l	#NewLoadRGB4,d0
		jsr	_LVOSetFunction(a6)

rp_failed2	move.l	_GfxBase,a1
		move.w	#_LVOSetRGB32CM,a0
		move.l	#NewSetRGB32CM,d0
		jsr	_LVOSetFunction(a6)

rp_failed1	move.l	_GfxBase,a1
		move.w	#_LVOLoadRGB32,a0
		move.l	#NewLoadRGB32,d0
		jsr	_LVOSetFunction(a6)

		jsr	_LVOPermit(a6)

		moveq	#-1,d0
		bra.s	rp_Finished

		ENDC



		; *** Bereche CorrectionTable ***

CalcCorrTab	movem.l	a2/d2-d4,-(sp)

		lea	CorrectionTable(pc),a0

		moveq	#0,d0			; d0=Helligkeitsstufe

cct_hell	moveq	#0,d1			; d1=beste Farbe (Nummer)
		move.b	#-1,d2			; d2=kleinster Fehler

		lea	LookupTable(pc),a1	; Reihenfolge der Prüfung
cct_loop	moveq	#0,d3			; auf Übereinstimmung
		move.b	(a1)+,d3
		bmi.s	cct_durch

		lea	A2024Table(pc),a2	; Helligkeit der Vergleichs-
		move.b	(a2,d3.w),d4		; farbe lesen

		sub.b	d0,d4			; Differenz zur Referenz-
		bpl.s	cct_skip		; helligkeit ermitteln
		neg.b	d4

cct_skip	cmp.b	d2,d4			; test, ob kleinerer Fehler
		bhs.s	cct_loop

		move.b	d3,d1			; neue beste Farbe
		move.b	d4,d2			; neuer kleinster Fehler
		bra.s	cct_loop

cct_durch	lea	A2024RGBTable(pc),a1	; R,G,B Werte aus der
		mulu	#6,d1			; A2024RGBTabelle auslesen
		add.w	d1,a1			; und in der CorrectionTable
		move.w	(a1)+,(a0)+		; auf 8 Byte-Grenzen ablegen
		move.w	(a1)+,(a0)+
		move.w	(a1)+,(a0)+
		clr.w	(a0)+

		addq.b	#1,d0			; alle Helligkeitsstufen
		bne.s	cct_hell		; 0-255 durchmachen

		movem.l	(sp)+,a2/d2-d4
		rts



		; *** Knoten Maintenance ***
		;
		; Alle Knoten löschen, wenn Patched=FALSE

		; To Do:
		; Knoten löschen, wenn ViewPort nicht mehr im Display

_MaintKnoten	move.l	a6,-(sp)

		move.l	Knotenliste+LH_HEAD(pc),a1  ; ersten Eintrag holen

mk_Liste	tst.l	LN_SUCC(a1)		; Liste zu Ende?
		beq.s	mk_Fertig
		move.l	LN_SUCC(a1),-(sp)	; Nächster Knoten -> a1

		tst.w	Patched			; Alles freigeben wenn
		beq.s	mk_Free			; Patch entfernt

		tst.w	_PatchActive		; oder wenn
		bne.s	mk_Next			; Patch inaktiv

mk_Free		tst.l	kn_RGBBuf(a1)		; Check for RGBBuffer
		beq.s	mk_FreeAltCMap
		move.l	a1,-(sp)		, Free RGB Buffer
		move.l	kn_RGBBuf(a1),a1
		move.l	4.w,a6
		jsr	_LVOFreeVec(a6)
		move.l	(sp)+,a1
mk_FreeAltCMap	tst.l	kn_AltCMap(a1)		; Check for Alt CMap
		beq.s	mk_FreeKnoten
		move.l	kn_AltCMap(a1),a0	; Free Alternate CMap
		clr.l	cm_PalExtra(a0)		; this is not _our_ PalExtra!
		move.l	_GfxBase,a6
		move.l	a1,-(sp)
		jsr	_LVOFreeColorMap(a6)
		move.l	(sp)+,a1
mk_FreeKnoten	move.l	4.w,a6			; Knoten freigeben
		jsr	_LVOFreeVec(a6)

mk_Next		move.l	(sp)+,a1
		bra.s	mk_Liste		; Schleife wiederholen

mk_Fertig	move.l	(sp)+,a6
		rts



		; *** FindeKnoten ***
		;
		; a0=ViewPort
		; -> d0=Knoten oder NULL bei Fehler
		; Zerstört KEINE Register außer D0

FindeKnoten	movem.l	d1-d3/a0/a1/a2/a6,-(sp)

		btst	#11-8,vp_Modes(a0)	; HAM Modus ($800)?
		bne	fk_Failure		; -> ja: Raus!

		tst.l	vp_ColorMap(a0)		; ColorMap vorhanden?
		beq.s	fk_Erlaubt
		move.l	vp_ColorMap(a0),a1
		tst.b	cm_Type(a1)		; alte (V34) ColorMap?
		beq.s	fk_Erlaubt
		move.l	cm_VPModeID(a1),d0	; A2024 Monitor ID?
		and.l	#MONITOR_ID_MASK,d0	; -> ja: Raus!
		cmp.l	#A2024_MONITOR_ID,d0
		beq	fk_Failure

fk_Erlaubt	move.l	Knotenliste+LH_HEAD(pc),a2  ; ersten Eintrag holen

fk_Liste	tst.l	LN_SUCC(a2)		; Liste zu Ende?
		beq.s	fk_NeuerKnoten
		cmp.l	kn_ViewPort(a2),a0	; stimmt ViewPort überein?
		beq.s	fk_Gefunden
		move.l	LN_SUCC(a2),a2		; Nächster Knoten
		bra.s	fk_Liste		; Schleife wiederholen

fk_Gefunden	tst.l	kn_AltCMap(a2)		; existiert eine AltCMap?
		beq	fk_KnotenA2
		move.l	vp_ColorMap(a0),a0	; AltCMap nochmals von der
		move.l	kn_AltCMap(a2),a1	; ursprüngl. ColorMap klonen
		bsr	CloneColorMap
		bra	fk_KnotenA2

fk_NeuerKnoten	moveq	#kn_Size,d0		; Speicher für Knoten belegen
		move.l	#MEMF_PUBLIC+MEMF_CLEAR,d1
		move.l	4.w,a6
		move.l	a0,-(sp)		; ViewPort retten
		jsr	_LVOAllocVec(a6)
		move.l	(sp)+,a0
		tst.l	d0
		beq	fk_Finished

		move.l	d0,a2			; Knoten ist in a1
		move.l	a0,kn_ViewPort(a2)	; Store ViewPort in Knoten

		move.l	vp_ColorMap(a0),a0	; Get ColorMap in a0
		moveq	#0,d0			; Get Color Count
		move.w	cm_Count(a0),d0
		move.l	_GfxBase,a6
		move.l	a0,-(sp)
		jsr	_LVOGetColorMap(a6)	; Get Alternate CMap
		move.l	(sp)+,a0

		move.l	d0,kn_AltCMap(a2)	; Store Alternate CMap
		beq.s	fk_Einklinken

		move.l	d0,a1			; Clone ColorMap
		bsr	CloneColorMap

		move.w	cm_Count(a0),d0		; calc size for RGB Buffer
		mulu	#12,d0			; 12*cm_Count+8
		addq.l	#8,d0
		move.l	#MEMF_PUBLIC,d1
		move.l	4.w,a6
		movem.l	a0/a1,-(sp)
		jsr	_LVOAllocVec(a6)
		movem.l	(sp)+,a0/a1
		move.l	d0,kn_RGBBuf(a2)
		beq.s	fk_Einklinken

		moveq	#0,d0			; start color
		moveq	#0,d1			; get color count
		move.w	cm_Count(a0),d1
		movem.l	a0/a1,-(sp)		; save CMap ptrs
		move.l	kn_RGBBuf(a2),a1	; get RGBBuf ptr + 4
		addq.w	#4,a1
		move.l	_GfxBase,a6
		jsr	_LVOGetRGB32(a6)
		movem.l	(sp)+,a0/a1

		moveq	#0,d0			; color counter
		move.l	a1,a0			; a0 is now AltCMap (!!!)
		move.l	kn_RGBBuf(a2),a1	; a1 is now RGBBuf (!!!)
		addq.w	#4,a1

fk_colors	movem.l	(a1)+,d1-d3		; get R,G,B values

		bsr	PatchColors		; patch R,G,B values

		movem.l	d0/a0/a1,-(sp)		; set patched color
		move.l	_GfxBase,a6		; in Alternate CMap
		pea	fk_uffz(pc)
		move.l	OldSetRGB32CM(pc),-(sp)
		rts
fk_uffz		movem.l	(sp)+,d0/a0/a1

		addq.w	#1,d0			; loop all colors
		cmp.w	cm_Count(a0),d0
		bne.s	fk_colors

fk_Einklinken	lea	Knotenliste(pc),a0	; Add Knoten to list
		move.l	a2,a1
		move.l	4.w,a6
		jsr	_LVOAddTail(a6)

fk_KnotenA2	move.l	a2,d0
fk_Finished	movem.l	(sp)+,d1-d3/a0/a1/a2/a6
		rts

fk_Failure	moveq	#0,d0			; return NULL (Failure)
		bra.s	fk_Finished


		; *** CloneColorMap ***

		; a0=SourceCMap
		; a1=DestCMap
		; Zerstört KEINE Register
		
CloneColorMap	movem.l	d0/d1/a0/a1/a6,-(sp)
		move.b	cm_Flags(a0),cm_Flags(a1)
		tst.b	cm_Type(a0)
		beq.s	ccm_OldStyle
		move.l	cm_vpe(a0),cm_vpe(a1)
		lea	cm_TransparencyPlane(a0),a0
		lea	cm_TransparencyPlane(a1),a1
		moveq	#cm_SIZEOF-cm_TransparencyPlane,d0
		move.l	4.w,a6
		jsr	_LVOCopyMem(a6)
ccm_OldStyle	movem.l	(sp)+,d0/d1/a0/a1/a6
		rts



		*** LoadRGB32 patch ***

		; a0=ViewPort
		; a1=Table

NL_REGS		REG	d2-d4/a2/a3

NewLoadRGB32	cmp.w	#0,a0			; kein ViewPort übergeben?
		beq.s	nl_QuickExit
		cmp.w	#0,a1			; keine Tabelle übergeben?
		beq.s	nl_QuickExit

		movem.l	NL_REGS,-(sp)

		tst.w	_PatchActive		; Check ob Patch aktiv
		beq.s	nl_NoPatch

		bsr	FindeKnoten		; Knoten auffinden oder
		tst.l	d0
		beq.s	nl_NoPatch		; erzeugen
		move.l	d0,a2			; Knoten -> a2

		tst.l	kn_AltCMap(a2)		; keine AltCMap?
		beq.s	nl_NoPatch

		tst.l	kn_RGBBuf(a2)		; kein RGBBuf?
		beq.s	nl_NoPatch

		tst.w	_UpdateAll		; Check ob alle Farben
		beq.s	nl_NoUpdateAll		; verändert werden müssen
		bra	nl_UpdateAll

nl_NoPatch	movem.l	(sp)+,NL_REGS		; keinen Patch durchführen
		move.l	OldLoadRGB32(pc),-(sp)	; original LoadRGB32 benutzen
nl_QuickExit	rts

		; übergebene Farben mittels ORIGINAL SetRGB32CM
		; in original CMap kopieren, patchen und
		; eine Tabelle aufbauen.

nl_NoUpdateAll	move.l	kn_RGBBuf(a2),a3	; RGBBuffer in a3
		move.l	a3,-(sp)

nl_GetCount	move.w	(a1)+,d4		; get count in d4
		move.w	d4,(a3)+
		beq.s	nl_TabEnde
		subq.w	#1,d4			; use for dbra
	
		moveq	#0,d0			; get offset in d0
		move.w	(a1)+,d0
		move.w	d0,(a3)+

nl_EntryLoop	movem.l	(a1)+,d1-d3		; get supplied colors

		movem.l	a0-a1/d0-d3,-(sp)	; set original colors
		move.l	vp_ColorMap(a0),a0	; in original ColorMap
		pea	nl_uffz(pc)
		move.l	OldSetRGB32CM(pc),-(sp)
		rts
nl_uffz		movem.l	(sp)+,a0-a1/d0-d3

		bsr	PatchColors		; now patch colors

		movem.l	d1-d3,(a3)		; save patched colors in
		lea	12(a3),a3		; in alternate table

		addq.l	#1,d0			; increase color offset
		dbra	d4,nl_EntryLoop		; loop supplied entries
		bra.s	nl_GetCount		; check next count

nl_TabEnde	move.l	(sp)+,a1		; use RGBBuf as table
		bra	nl_ApplyTable

		; übergebene Farben mittels ORIGINAL SetRGB32CM
		; in original CMap kopieren.
		; dann ALLE Farben der original CMap patchen und
		; eine Tabelle aufbauen

nl_UpdateAll	move.w	(a1)+,d4		; get count in d3
		beq.s	nl_TabEnde2
		subq.w	#1,d4

		moveq	#0,d0			; get offset in d0
		move.w	(a1)+,d0

nl_EntryLoop2	movem.l	(a1)+,d1-d3		; get supplied colors

		movem.l	a0-a1/d0,-(sp)		; set original colors
		move.l	vp_ColorMap(a0),a0	; in original ColorMap
		pea	nl_uffz2(pc)
		move.l	OldSetRGB32CM(pc),-(sp)
		rts
nl_uffz2	movem.l	(sp)+,a0-a1/d0

		addq.l	#1,d0			; increase color offset
		dbra	d4,nl_EntryLoop2	; loop supplied entries
		bra.s	nl_UpdateAll		; check next count

nl_TabEnde2	move.l	kn_RGBBuf(a2),a1	; get RGBBuf in a1
		move.l	a1,-(sp)		; save RGBBuf

		move.l	a0,-(sp)		; save ViewPort
		move.l	vp_ColorMap(a0),a0	; get ColorMap in a0
		moveq	#0,d4			; get color count in d4
		move.w	cm_Count(a0),d4
		move.w	d4,(a1)+		; store count in RGBBuf
		clr.w	(a1)+			; store offset in RGBBuf
		moveq	#0,d0			; firstcolor=0
		move.l	d4,d1			; numcolors
		move.l	a1,-(sp)
		jsr	_LVOGetRGB32(a6)	; get 32 bit RGB values
		move.l	(sp)+,a1
		move.l	(sp)+,a0		; restore ViewPort

		subq.w	#1,d4			; d4=colorcount for dbra
nl_patch	movem.l	(a1),d1-d3		; get 32 bit R,G,B
		bsr	PatchColors		; patch colors
		movem.l	d1-d3,(a1)		; replace original colors
		lea	12(a1),a1		; with patched ones in table
		dbra	d4,nl_patch		; loop all colors
		clr.w	(a1)+			; clear last count (end mark)

		move.l	(sp)+,a1		; use RGBBuf as table

		; erzeugte Tabelle auf AltCMap anwenden

nl_ApplyTable	move.l	vp_ColorMap(a0),-(sp)	; save orig ColorMap
		move.l	a0,-(sp)		; save VPort ptr

		move.l	a6,-(sp)		; forbid multitasking
		move.l	4.w,a6
		jsr	_LVOForbid(a6)
		move.l	(sp)+,a6

		move.l	kn_AltCMap(a2),vp_ColorMap(a0)	; use alt CMap in VPort
		pea	nl_Return(pc)
		move.l	OldLoadRGB32(pc),-(sp)	; do original LoadRGB32
		rts
nl_Return	move.l	(sp)+,a0		; restore VPort
		move.l	(sp)+,vp_ColorMap(a0)	; restore CMap in VPort

		move.l	a6,-(sp)		; permit multitasking
		move.l	4.w,a6
		jsr	_LVOPermit(a6)
		move.l	(sp)+,a6

		movem.l	(sp)+,NL_REGS
		rts



		; *** SetRGB32CM patch ***

		; a0=ColorMap
		; d0=Color
		; d1=32 bit red
		; d2=32 bit green
		; d3=32 bit blue

NS_REGS		EQUR	d2-d4/a2

NewSetRGB32CM	cmp.w	#0,a0			; no ColorMap given?
		beq.s	ns_QuickExit

		movem.l	d0/d1/a0,-(sp)		; use original SetRGB32CM
		pea	ns_Return(pc)
		move.l	OldSetRGB32CM(pc),-(sp)
		rts
ns_Return	movem.l	(sp)+,d0/d1/a0

		movem.l	NS_REGS,-(sp)

		tst.w	_PatchActive		; Check ob Patch aktiv
		beq.s	ns_NoPatch

		tst.b	cm_Type(a0)		; Check ob V36 CMap
		beq.s	ns_NoPatch

		tst.l	cm_vp(a0)		; Link zu ViewPort?
		beq.s	ns_NoPatch

		movem.l	a0/d0,-(sp)
		move.l	cm_vp(a0),a0
		bsr	FindeKnoten		; Knoten auffinden
		move.l	d0,a2			; oder erzeugen
		movem.l	(sp)+,a0/d0
		cmp.w	#0,a2
		beq.s	ns_NoPatch

		tst.l	kn_AltCMap(a2)		; keine AltCMap?
		beq.s	ns_NoPatch

		tst.l	kn_RGBBuf(a2)		; kein RGBBuf?
		beq.s	ns_NoPatch

		; patch the color values and enter in the
		; alternate ColorMap as well

		bsr	PatchColors
		move.l	kn_AltCMap(a2),a0
		pea	ns_NoPatch(pc)
		move.l	OldSetRGB32CM(pc),-(sp)
		rts

ns_NoPatch	movem.l	(sp)+,NS_REGS
ns_QuickExit	rts



		; *** LoadRGB4 patch ***

		; a0=ViewPort
		; a1=Colors
		; d0.w=Count

L4_REGS		REG	d2-d5/a2/a3

NewLoadRGB4	cmp.w	#0,a0			; kein ViewPort übergeben?
		beq.s	l4_QuickExit
		cmp.w	#0,a1			; keine Tabelle übergeben?
		beq.s	l4_QuickExit

		movem.l	L4_REGS,-(sp)

		tst.w	_PatchActive		; Check ob Patch aktiv
		beq.s	l4_NoPatch

		move.w	d0,-(sp)
		bsr	FindeKnoten		; Knoten auffinden oder
		move.l	d0,a2			; erzeugen, Knoten -> a2
		move.w	(sp)+,d0
		cmp.w	#0,a2
		beq.s	l4_NoPatch

		tst.l	kn_AltCMap(a2)		; keine AltCMap?
		beq.s	l4_NoPatch

		tst.l	kn_RGBBuf(a2)		; kein RGBBuf?
		beq.s	l4_NoPatch

		bra	l4_Patch

l4_NoPatch	movem.l	(sp)+,L4_REGS		; keinen Patch durchführen
		move.l	OldLoadRGB4(pc),-(sp)	; original LoadRGB32 benutzen
l4_QuickExit	rts

l4_Patch	; übergebene Farben mittels ORIGINAL SetRGB32CM
		; in original CMap kopieren, patchen und
		; eine Tabelle aufbauen.

l4_NoUpdateAll	move.l	kn_RGBBuf(a2),a3	; RGBBuffer in a3
		move.l	a3,-(sp)

l4_GetCount	move.w	d0,d4			; get count in d4
		move.w	d4,(a3)+		; store count
		subq.w	#1,d4			; use for dbra
		moveq	#0,d0			; get offset in d0
		move.w	d0,(a3)+		; store offset

l4_EntryLoop	moveq	#0,d1
		move.w	(a1)+,d1		; get RGB4 colors in d1
		move.l	d1,d2
		move.l	d1,d3

		and.w	#$0f00,d1		; create 32bit red
		move.w	d1,d5
		lsl.w	#4,d1
		or.w	d5,d1
		swap	d1

		and.w	#$00f0,d2		; create 32bit green
		lsl.w	#4,d2
		move.w	d2,d5
		lsl.w	#4,d2
		or.w	d5,d2
		swap	d2

		and.w	#$000f,d3		; create 32bit blue
		lsl.w	#8,d3
		move.w	d3,d5
		lsl.w	#4,d3
		or.w	d5,d3
		swap	d3

		movem.l	a0-a1/d0-d3,-(sp)	; set original colors
		move.l	vp_ColorMap(a0),a0	; in original ColorMap
		pea	l4_uffz(pc)
		move.l	OldSetRGB32CM(pc),-(sp)
		rts
l4_uffz		movem.l	(sp)+,a0-a1/d0-d3

		bsr	PatchColors		; now patch colors

		movem.l	d1-d3,(a3)		; save patched colors in
		lea	12(a3),a3		; in alternate table

		addq.l	#1,d0			; increase color offset
		dbra	d4,l4_EntryLoop		; loop supplied entries

		clr.w	(a3)+			; set count to 0 (end mark)
		move.l	(sp)+,a1		; use RGBBuf as table

		; erzeugte Tabelle auf AltCMap anwenden

l4_ApplyTable	move.l	vp_ColorMap(a0),-(sp)	; save orig ColorMap
		move.l	a0,-(sp)		; save VPort ptr

		move.l	a6,-(sp)		; forbid multitasking
		move.l	4.w,a6
		jsr	_LVOForbid(a6)
		move.l	(sp)+,a6

		move.l	kn_AltCMap(a2),vp_ColorMap(a0)	; use alt CMap in VPort
		pea	l4_Return(pc)
		move.l	OldLoadRGB32(pc),-(sp)	; do original LoadRGB32
		rts
l4_Return	move.l	(sp)+,a0		; restore VPort
		move.l	(sp)+,vp_ColorMap(a0)	; restore CMap in VPort

		move.l	a6,-(sp)		; permit multitasking
		move.l	4.w,a6
		jsr	_LVOPermit(a6)
		move.l	(sp)+,a6

		movem.l	(sp)+,L4_REGS
		rts



		; *** MakeVPort patch ***

		; a0=View
		; a1=ViewPort

MV_REGS		EQUR	a2

NewMakeVPort	cmp.w	#0,a0			; no View given?
		beq.s	mv_QuickExit
		cmp.w	#0,a1			; no ViewPort given?
		beq.s	mv_QuickExit

		move.l	MV_REGS,-(sp)

		tst.w	_PatchActive		; Check ob Patch aktiv
		beq.s	mv_NoPatch

		move.l	a0,-(sp)
		move.l	a1,a0
		bsr	FindeKnoten		; Knoten auffinden oder
		move.l	(sp)+,a0		; erzeugen
		tst.l	d0
		beq.s	mv_NoPatch
		move.l	d0,a2			; Knoten -> a2

		tst.l	kn_AltCMap(a2)		; keine AltCMap?
		beq.s	mv_NoPatch

		tst.l	kn_RGBBuf(a2)		; kein RGBBuf?
		beq.s	mv_NoPatch

		bra.s	mv_Patch

mv_NoPatch	move.l	(sp)+,MV_REGS		; keinen Patch durchführen
		move.l	OldMakeVPort(pc),-(sp)	; original MakeVPort benutzen
		rts

mv_Patch	move.l	vp_ColorMap(a1),-(sp)	; save orig ColorMap
		move.l	a1,-(sp)		; save VPort ptr

		move.l	a6,-(sp)		; forbid multitasking
		move.l	4.w,a6
		jsr	_LVOForbid(a6)
		move.l	(sp)+,a6

		move.l	kn_AltCMap(a2),vp_ColorMap(a1)	; use alt CMap in VPort
		pea	mv_Return(pc)
		move.l	OldMakeVPort(pc),-(sp)	; do original MakeVPort
		rts
mv_Return	move.l	(sp)+,a1		; restore VPort
		move.l	(sp)+,vp_ColorMap(a1)	; restore CMap in VPort

		move.l	a6,-(sp)		; permit multitasking
		move.l	4.w,a6
		jsr	_LVOPermit(a6)
		move.l	(sp)+,a6

		move.l	(sp)+,MV_REGS
mv_QuickExit	rts



		; *** LoadView Patch ***
		;
		; a1=View

LV_REGS		EQUR	a2


NewLoadView	move.l	LV_REGS,-(sp)

		tst.w	_PatchActive		; is patch active?
		beq.s	lv_NoPatch

		cmp.w	#0,a1			; no view given?
		beq.s	lv_NoPatch		; -> use orig function

		tst.l	v_ViewPort(a1)		; no viewports?
		beq.s	lv_NoPatch

		bra.s	lv_Patch

lv_NoPatch	move.l	(sp)+,LV_REGS
		move.l	OldLoadView(pc),-(sp)
		rts

		; Die ColorMaps aller sichtbaren Views
		; gegen die alternativen austauschen,
		; dann LoadView aufrufen und die Änderungen
		; rückgängig machen

lv_Patch	move.l	a6,-(sp)		; disable multitasking
		move.l	4.w,a6
		jsr	_LVOForbid(a6)
		move.l	(sp)+,a6

		clr.l	-(sp)			; end marker for stack frame

		move.l	v_ViewPort(a1),a0

lv_Loop		btst	#13-8,vp_Modes(a0)	; viewport hidden?
		bne.s	lv_Invisible		; ->ignore

		bsr	FindeKnoten		; Knoten auffinden oder 
		tst.l	d0			; erzeugen
		beq.s	lv_Invisible
		move.l	d0,a2

		tst.l	kn_AltCMap(a2)		; no AltCMap?
		beq.s	lv_Invisible

		tst.l	kn_RGBBuf(a2)		; no RGBBuf?
		beq.s	lv_Invisible

		move.l	vp_ColorMap(a0),-(sp)	; ColorMap und ViewPort
		move.l	a0,-(sp)		; auf dem Stack sichern

		move.l	kn_AltCMap(a2),vp_ColorMap(a0)	; use alt CMap

lv_Invisible	move.l	vp_Next(a0),a0		; loop all ViewPorts
		cmp.w	#0,a0
		bne.s	lv_Loop

		pea	lv_Return(pc)		; use original LoadView
		move.l	OldLoadView(pc),-(sp)	; function
		rts

lv_Return	move.l	(sp)+,a0		; alte ColorMaps wieder
		cmp.w	#0,a0			; in ViewPorts eintragen
		beq.s	lv_Fertig
		move.l	(sp)+,vp_ColorMap(a0)
		bra.s	lv_Return

lv_Fertig	move.l	a6,-(sp)		; reenable multitasking
		move.l	4.w,a6
		jsr	_LVOPermit(a6)
		move.l	(sp)+,a6

		move.l	(sp)+,LV_REGS
		rts



		; *** PatchColors ***

		; d1 = 32bit RED
		; d2 = 32bit GREEN
		; d3 = 32bit BLUE
		; -> d1,d2,d3 patched 32bit RGB
		; Zerstört KEINE Register

PatchColors	move.l	d0,-(sp)

		rol.l	#8,d1			; rotate 8 bit R,G,B
		rol.l	#8,d2			; in d1.b,d2.b,d3.b
		rol.l	#8,d3

		moveq	#0,d0			; create $ff.l in d0
		move.b	#$ff,d0

		and.l	d0,d1			; create 8 bit R,G,B
		and.l	d0,d2			; in d1.l,d2.l,d3.l
		and.l	d0,d3

		addq.w	#1,d0			; create $100.l in d0

		cmp.w	_RedVal(pc),d0
		beq.s	.skipred
		muls	_RedVal(pc),d1
		asr.l	#8,d1
.skipred

		cmp.w	_GreenVal(pc),d0
		beq.s	.skipgreen
		muls	_GreenVal(pc),d2
		asr.l	#8,d2
.skipgreen

		cmp.w	_BlueVal(pc),d0
		beq.s	.skipblue
		muls	_BlueVal(pc),d3
		asr.l	#8,d3
.skipblue

		move.w	_ColorVal(pc),d0
		cmp.w	#256,d0
		beq.s	.skipcolor
		neg.w	d0
		add.w	#256,d0

		movem.l	d4/d5,-(sp)

		move.l	d1,d4		; calc color average
		add.w	d2,d4
		add.w	d3,d4
		divu	#3,d4		; alternative 1

*		moveq	#0,d5		; alternative 2
*		add.w	_RedVal(pc),d5
*		add.w	_GreenVal(pc),d5
*		add.w	_BlueVal(pc),d5
*		asl.l	#8,d4
*		divs	d5,d4

		move.w	d4,d5		; adjust red value
		sub.w	d1,d5
		muls.w	d0,d5
		asr.l	#8,d5
		add.w	d5,d1

		move.w	d4,d5		; adjust green value
		sub.w	d2,d5
		muls.w	d0,d5
		asr.l	#8,d5
		add.w	d5,d2

		move.w	d4,d5		; adjust blue value
		sub.w	d3,d5
		muls.w	d0,d5
		asr.l	#8,d5
		add.w	d5,d3

		movem.l	(sp)+,d4/d5
.skipcolor

		move.w	_ContrVal(pc),d0
		cmp.w	#256,d0
		beq.s	.skipcontr
		neg.w	d0
		add.w	#256,d0

		move.l	d4,-(sp)

		moveq	#$7f,d4		; adjust red value
		sub.w	d1,d4
		muls.w	d0,d4
		asr.l	#8,d4
		add.w	d4,d1

		moveq	#$7f,d4		; adjust green value
		sub.w	d2,d4
		muls.w	d0,d4
		asr.l	#8,d4
		add.w	d4,d2

		moveq	#$7f,d4		; adjust blue value
		sub.w	d3,d4
		muls.w	d0,d4
		asr.l	#8,d4
		add.w	d4,d3

		move.l	(sp)+,d4
.skipcontr

		move.w	_BrightVal(pc),d0
		cmp.w	#256,d0
		beq.s	.skipbright
		muls.w	d0,d1
		muls.w	d0,d2
		muls.w	d0,d3
		asr.l	#8,d1
		asr.l	#8,d2
		asr.l	#8,d3
.skipbright

		tst.w	d1		; fix R,G,B negative overflow
		bpl.s	.posred
		moveq	#0,d1
.posred		tst.w	d2
		bpl.s	.posgreen
		moveq	#0,d2
.posgreen	tst.w	d3
		bpl.s	.posblue
		moveq	#0,d3
.posblue

		move.w	#$ff,d0		; fix R,G,B positive overflow
		cmp.w	d0,d1
		bls.s	.goodred
		move.w	d0,d1
.goodred	cmp.w	d0,d2
		bls.s	.goodgreen
		move.w	d0,d2
.goodgreen	cmp.w	d0,d3
		bls.s	.goodblue
		move.w	d0,d3
.goodblue

		tst.w	_CorA2024Active	; a2024 correction
		beq.s	.skipcor

		move.l	d1,d0		; calc color brightness
		add.w	d2,d0
		add.w	d3,d0
		divu	#3,d0

		lsl.w	#3,d0		; get R,G,B values corresponding
		move.l	a0,-(sp)	; to brightness
		lea	CorrectionTable(pc),a0
		movem.w	(a0,d0.w),d1-d3
		move.l	(sp)+,a0
.skipcor

		tst.w	_EmuA2024Active	; a2024 emulation
		beq.s	.skipemu

		moveq	#0,d0		; clear offset counter

		roxl.b	#1,d1		; bit 3 red = 1st line high bit
		roxl.b	#1,d0

		roxl.b	#1,d3		; bit 3 blue = 1st line low bit
		roxl.b	#1,d0

		roxl.b	#1,d2		; bit 3 green = 2nd line high bit
		roxl.b	#1,d0

		lsl.b	#2,d3		; skip 2 bits blue
		roxl.b	#1,d3		; bit 0 blue = 2nd line low bit
		roxl.b	#1,d0

		move.l	a0,-(sp)	; get grey value from table
		lea	A2024Table(pc),a0
		move.b	(a0,d0.w),d1
		move.b	d1,d2
		move.b	d1,d3
		move.l	(sp)+,a0
.skipemu

		ror.l	#8,d1		; 32 bit R,G,B Werte herstellen
		ror.l	#8,d2
		ror.l	#8,d3

		move.l	(sp)+,d0
		rts



		*** Variablen ***

		XREF	_GfxBase

		XDEF	_PatchActive
_PatchActive	dc.w	1
		XDEF	_UpdateAll
_UpdateAll	dc.w	0
		XDEF	_CorA2024Active
_CorA2024Active	dc.w	0
		XDEF	_EmuA2024Active
_EmuA2024Active	dc.w	0
		XDEF	_RedVal
_RedVal		dc.w	256
		XDEF	_GreenVal
_GreenVal	dc.w	256
		XDEF	_BlueVal
_BlueVal	dc.w	256
		XDEF	_BrightVal
_BrightVal	dc.w	256
		XDEF	_ColorVal
_ColorVal	dc.w	256
		XDEF	_ContrVal
_ContrVal	dc.w	256

OldLoadRGB32	dc.l	0
OldSetRGB32CM	dc.l	0
OldLoadRGB4	dc.l	0
OldMakeVPort	dc.l	0
OldLoadView	dc.l	0
Patched		dc.w	0
Knotenliste	ds.b	MLH_SIZE

A2024Table	dc.b	$00,$66,$77,$AA		; subjektive Helligkeits-
		dc.b	$66,$88,$99,$CC		; werte aller 16 möglichen
		dc.b	$77,$99,$BB,$DD		; A2024-"Farben"
		dc.b	$AA,$CC,$DD,$FF

*A2024Table	dc.b	$00,$22,$44,$AA		; alternative Tabelle
*		dc.b	$22,$66,$88,$DD		; weniger Kontrast, aber
*		dc.b	$44,$88,$CC,$EE		; mehr Details
*		dc.b	$AA,$DD,$EE,$FF

A2024RGBTable	dc.w	$00,$00,$00		; die R,G,B Werte aller 16
		dc.w	$00,$00,$88		; möglichen A2024-"Farben"
		dc.w	$88,$00,$00
		dc.w	$88,$00,$88

		dc.w	$00,$00,$11
		dc.w	$00,$00,$99
		dc.w	$88,$00,$11
		dc.w	$88,$00,$99

		dc.w	$00,$88,$00
		dc.w	$00,$88,$88
		dc.w	$88,$88,$00
		dc.w	$88,$88,$88

		dc.w	$00,$88,$11
		dc.w	$00,$88,$99
		dc.w	$88,$88,$11
		dc.w	$88,$88,$99

LookupTable	dc.b	$0,$5,$A,$F		; Reihenfolge der Graustufen
		dc.b	$1,$6,$B		; für die Berechnung der
		dc.b	$2,$7			; CorrectionTable, optimiert auf
		dc.b	$3			; möglichst "reine" Graustufen.
		dc.b	-1
		even

CorrectionTable	ds.w	256*4			; 4 Words pro Helligkeitsstufe
