// ConvertPut.bcpl -- scan conversion write into buffer

//  errors 700

get "PDInternals.d"
get "PDConvert.d"
get "AltoDefs.d"

// outgoing procedures
external
	[
	PutInit
	PutFinish
	PutNewColor
	PutRun
	PutBits
	]

// incoming procedures
external
	[
//ConvertColor
	ColorGetLine
//ConvertUtils
	LoadRead
	LoadReadBlock
	GetBBT
	PutBBT
//WINDOW
	WindowReadBlock
//PDPRINT
	FSGetX
	FSPutZ
	PDError
//PDML
	BitBLT
	Zero
	MulFull
	]

// incoming statics
external
	[
	PDWindow
	bandBuffer
	FMin
	FMax
	FWC
	colorLine
	colorType
	colorTransparent
	LoadBase
	UseXM
	]

// internal statics
static
	[
	maskLine		//Single scan-line buffer
	bb		//BitBLT table
	bba		//BitBLT table for "and"ing color and mask
	]

// PutInit()
// Set up buffers, etc. for Put routines

let PutInit() be
[
// Make up BitBlt control table for common cases
	bb=GetBBT()
	if bandBuffer eq 0 then PDError(700)
	bb>>BBT.dbca=bandBuffer
	bb>>BBT.dbmr=FWC
//	bb>>BBT.dh=1		//single scan-line in destination
//	bb>>BBT.sbmr=FWC
//	bb>>BBT.sty=0
// Set up temporary storage for mask for PutBits
	maskLine=FSGetX(FWC)	//single scan-line buffer for PutBits
// BitBlt table for anding color and mask into maskLine
	bba=GetBBT()
	bba>>BBT.sType=sNotBM
	bba>>BBT.op=fErase
	bba>>BBT.dbca=maskLine
	bba>>BBT.dbmr=FWC
//	bba>>BBT.dlx=0
//	bba>>BBT.dty=0
	bba>>BBT.dh=1		//single scan-line in destination
	if colorLine eq 0 then PDError(700)
	bba>>BBT.sbca=colorLine
	bba>>BBT.sbmr=FWC
//	bba>>BBT.sty=0
]

and PutFinish() be
[
	FSPutZ(lv maskLine)
	PutBBT(lv bb)
	PutBBT(lv bba)
]

and PutNewColor() be
[
	for i=0 to 3 do bb>>BBT.gray↑i=((colorType eq loColorClear)? 0,-1)
]

// PutRun(sFirst, sLast, fMin, fSize)
// Put out a run indicated, on scan-lines [sFirst..sLast] (relative to beginning of band.)

and PutRun(sFirst, sLast, fMin, fSize) be
[
	let fMax=fMin+fSize-1
//First, check for out of bounds
	if fMin ugr fMax % fMin uls FMin % fMax ugr FMax then
		PDError(701)
	let fLeft=fMin-FMin
	bb>>BBT.dlx=fLeft
	bb>>BBT.dw=fSize
	bb>>BBT.op=(colorTransparent? fPaint,fReplace)
	test colorType le loColorClear then
	[
		bb>>BBT.dty=sFirst
		bb>>BBT.dh=sLast-sFirst+1
		bb>>BBT.sType=sGray
		BitBLT(bb)
	] or [
		bb>>BBT.dh=1
		bb>>BBT.sType=sBM
		bb>>BBT.sbca=colorLine
		bb>>BBT.sbmr=FWC
		bb>>BBT.slx=fLeft
		for s=sFirst to sLast do
			[
			ColorGetLine(s)		//Obtain color data for this scan line
			bb>>BBT.dty=s
			BitBLT(bb)
			]
	]
]

// PutBits(sFirst, sLast, fMin, fSize, pos, color)
// Put out scan-line of bits on scan-lines [sFirst..sLast] (relative to beginning of
// band).
// Obtain bits from pos, which is positioned at the right scan-line.
// If "color" <>0, sample data is to be stored into buffer, irrespective
//		of current color settings

and PutBits(sFirst, sLast, fMin, fSize, pos, color) be
[
	let fMax=fMin+fSize-1
//First, check for out of bounds
	if fMin ugr fMax % fMin uls FMin % fMax ugr FMax then
		PDError(701)
//Set up BitBlt parameters
	let fLeft=fMin-FMin
	let maskWC=(fSize+15) rshift 4
	bb>>BBT.sType=sBM
	bb>>BBT.dlx=fLeft
	bb>>BBT.dw=fSize
	bb>>BBT.slx=0
//Decide if it's a simple case that can be done in one BitBLT
	test colorType le loColorClear & @pos ne -1 & color eq 0 then
[
	bb>>BBT.sbca=@pos+LoadBase	//Core address
	bb>>BBT.sBank=UseXM
	bb>>BBT.sbmr=maskWC
	let hgh=sLast-sFirst+1
	bb>>BBT.dty=sFirst
	bb>>BBT.dh=hgh
	bb>>BBT.op=(colorType eq loColorInk)? fPaint, fErase
	BitBLT(bb)
	bb>>BBT.sBank=0		//Put this back
	let len=vec 1
	MulFull(maskWC, hgh, len)
	if len!0 ne 0 then PDError(702)
	@pos=@pos+len!1
] or [
	bb>>BBT.dh=1
	bb>>BBT.sbca=maskLine
	bb>>BBT.sbmr=FWC	
	for s=sFirst to sLast do
	[
		bb>>BBT.dty=s
//Read mask bits into maskLine
		test @pos eq -1 then WindowReadBlock(PDWindow, maskLine, maskWC)
		 or [ LoadReadBlock(@pos, maskLine, maskWC); @pos=@pos+maskWC ]
//Do the right kind of BitBLT
		test color ne 0 then
		[
			bb>>BBT.op=fReplace
			BitBLT(bb)
		] or
		test colorType eq loColorInk then
		[
			bb>>BBT.op=fPaint
			BitBLT(bb)
		] or 
		test colorType eq loColorClear then
		[
			bb>>BBT.op=fErase
			BitBLT(bb)
		] or [
			ColorGetLine(s)		//Obtain color data for this scan line
			unless colorTransparent then	//Write 0's under mask if opaque
				[
				bb>>BBT.op=fErase
				BitBLT(bb)
				]
			//Now "and" color data into mask data
			bba>>BBT.dw=fSize
			bba>>BBT.slx=fLeft
			BitBLT(bba)
			//Now "or" maskLine into bandBuffer
			bb>>BBT.op=fPaint
			BitBLT(bb)
		]
	]
]
]