// S C A N P U T D O T S
// This code is never run-- microcode does it all

get "PressInternals.df"
get "PressParams.df"

// outgoing procedures
external
	[
	ScanPutDots
	ScanPutHalfTone
	]

// incoming procedures
external
	[
//PRESS
	PressError

//PRESSML
	Ugt
	]

// incoming statics
external
	[
	mpSBuf	//Map from scan-line to buffer
	ScanBuf	//core buffer
	]

//ScanPutDots(s,v)
// Puts out one scanline of dots.  S is scanline number (0 to BANDWidth-1)
// v is pointer to BEDots entry.
// **** This routine also in microcode ****

let ScanPutDots(s,v) be
 [
   let Bdim=v>>BEDots.Bdim	// - # bits to output
   let Bcount=DotsDeltaConst
   let Bmagnify=v>>BEDots.Bmagnify

   let wordout=0				//Output word
   let Bbit=(v>>BEDots.Bstart)&#17
   let Bword=mpSBuf!s+(v>>BEDots.Bstart rshift 4)
   let Bincr=v>>BEDots.Bincr
   let Bit=nil
   let InBit=(#20-v>>BEDots.BitPhase)

   let InAdr=v>>BEDots.BitBuf
   let wordin=@InAdr
   InAdr=InAdr+1

[
   [

//Getabit
   if InBit eq 0 then
	[
	InBit=#20
	wordin=@InAdr
	InAdr=InAdr+1
	]
   let mask=(table [	0;#1;#2;#4;#10;#20;#40;
			#100;#200;#400;#1000;#2000;#4000;
			#10000;#20000;#40000;#100000 ] )!InBit
   InBit=InBit-1
   Bit=(wordin&mask)

   if Bmagnify then break
   Bcount=Bcount-v>>BEDots.Bdelta
   if Bcount ls 0 then
	[
	Bcount=Bcount+DotsDeltaConst
	break
	]
   ] repeat

   [

//Putabit
   if Bit then
	[
	let OrBit=(table [	#100000;#40000;#20000;#10000;
			#4000;#2000;#1000;#400;#200;#100;
			#40;#20;#10;#4;#2;#1 ] )!Bbit
	wordout=wordout%OrBit
	]
   Bbit=Bbit+Bincr
   if (Bbit&#177760) ne 0 then
	[
	Bbit=(Bincr ls 0)? 15,0
	compileif DebugSw then
	   [
	   let ScanBufLast=ScanBuf-(ScanBuf!-1)-2
	   if Ugt(ScanBuf,Bword) % Ugt(Bword,ScanBufLast) then PressError(1601)
	   ]
	@Bword=@Bword%wordout	//No opaque yet
	Bword=Bword+Bincr
	wordout=0
	]
   Bdim=Bdim+1
   if Bdim eq 0 then
	[
	@Bword=@Bword%wordout
	return			//All done!
	]

   unless Bmagnify then break
   Bcount=Bcount-v>>BEDots.Bdelta
   if Bcount ls 0 then
	[
	Bcount=Bcount+DotsDeltaConst
	break
	]
   ] repeat

] repeat				//Many, many bits!

]

//ScanPutHalfTone(s,v)
// Puts out one scanline of dots.  S is scanline number (0 to BANDWidth-1)
// v is pointer to BEDots entry.
// **** This routine also in microcode ****

and ScanPutHalfTone(s,v) be
 [
   let Bdim=v>>BEDots.Bdim	// - # bits to output
   let Bcount=DotsDeltaConst
   let Bmagnify=v>>BEDots.Bmagnify

   let wordout=0				//Output word
   let Bbit=(v>>BEDots.Bstart)&#17
   let Bword=mpSBuf!s+(v>>BEDots.Bstart rshift 4)
   let Bincr=v>>BEDots.Bincr
   let Sample=nil
   let sampleSize=v>>BEDots.Code
   let InSample=(#20-(v>>BEDots.BitPhase)*sampleSize)

   let InAdr=v>>BEDots.BitBuf
   let wordin=@InAdr
   InAdr=InAdr+1

   let Mask=-1 rshift (16-sampleSize)

   let OrBitTable=
	table [	#100000;#40000;#20000;#10000;
		#4000;#2000;#1000;#400;#200;#100;
		#40;#20;#10;#4;#2;#1 ] 

   let screenAddr=v>>BEDots.ScreenAddress
   let screenMod=v>>BEDots.ScreenModulus
   let screenCount=0
   let screen=0		//if screening, put screen value here

   //the following variables can be S registers in the microcode implementation
   let CascadeDiag=0		//error moving diagonally
   let black=v>>BEDots.IMin
   let white=v>>BEDots.IMax
   let range=(white-black)*4
   let threshold=black-white
   let error=0		//holds 50% error moving from left, and is also used as a temp
   let error1=0		//holds 25% error
   let ErrorBuffer=v>>BEDots.ErrorBuffer-Bdim	//indexed by Bdim
							//since Bdim<0, add in -Bdim
[
   [

//Get a sample point
   if InSample ls sampleSize then
	[
	InSample=#20
	wordin=@InAdr
	InAdr=InAdr+1
	]
   InSample=InSample-sampleSize
   Sample=((wordin rshift InSample)&Mask)-black
   Sample=Sample*4		//*4 to avoid errors on 25% error calculation

   if Bmagnify then break
   Bcount=Bcount-v>>BEDots.Bdelta
   if Bcount ls 0 then
	[
	Bcount=Bcount+DotsDeltaConst
	break
	]
   ] repeat

   [ //Put out next bit(s) for this sample point

      //add screen frequency, if called for
      unless screenAddr eq 0 do
	 [ screen=screenAddr!screenCount
	   screenCount=(screenCount+1) rem screenMod
       ]

     //read incoming error value
     error=ErrorBuffer!Bdim + error	//down error from last line + error from left

     error=error-(Sample+screen)
     test error ge threshold 
	then wordout=wordout%(OrBitTable!Bbit)
	or error=error+range

     //now, compute cascading error to put out
     // distribution is : Down 25%, Diag 25%, Right 50%
     error=error/2	//50% error (error is a signed number)
     error1=error/2	//25% error
     ErrorBuffer!Bdim=CascadeDiag+error1	//previous diagonal error + new down error
     CascadeDiag=error1	

   Bbit=Bbit+Bincr
   if (Bbit&#177760) ne 0 then
	[
	Bbit=(Bincr ls 0)? 15,0
	compileif DebugSw then
	   [
	   let ScanBufLast=ScanBuf-(ScanBuf!-1)-2
	   if Ugt(ScanBuf,Bword) % Ugt(Bword,ScanBufLast) then PressError(1601)
	   ]
	@Bword=@Bword%wordout	//No opaque yet
	Bword=Bword+Bincr
	wordout=0
	]
   Bdim=Bdim+1
   if Bdim eq 0 then
	[
	@Bword=@Bword%wordout
	return			//All done!
	]

   unless Bmagnify then break
   Bcount=Bcount-v>>BEDots.Bdelta
   if Bcount ls 0 then
	[
	Bcount=Bcount+DotsDeltaConst
	break
	]
   ] repeat

] repeat				//Many, many bits!

]