--MUST BE COMPILED WITH /L SWITCH DIRECTORY AltoMicrocodeDefs: FROM "AltoMicrocodeDefs", D0MicrocodeDefs: FROM "D0MicrocodeDefs" USING [JumpRamArgRslt], HalftoneDefs: FROM "HalftoneDefs", InlineDefs: FROM "InlineDefs" USING [BITSHIFT,BITOR,BITAND,LongMult,LongDiv,HighHalf,LowHalf], GraphicsDefs: FROM "GraphicsDefs" USING [Bitmap,GetDefaultBitmapHandle], LongDefs: FROM "LongDefs", MiscDefs: FROM "MiscDefs" USING [SetBlock], SegmentDefs: FROM "SegmentDefs", SystemDefs: FROM "SystemDefs"; HalftoneImpl: PROGRAM IMPORTS AltoMicrocodeDefs, D0MicrocodeDefs, GraphicsDefs, InlineDefs, LongDefs, SegmentDefs, MiscDefs, SystemDefs EXPORTS HalftoneDefs = BEGIN OPEN HalftoneDefs, GraphicsDefs, MiscDefs; htMicrocodeStart: CARDINAL = 7400B; machine: SegmentDefs.MachineType _ SegmentDefs.GetMemoryConfig[].AltoType; UseMicrocode: BOOLEAN _ machine IN [AltoIIXM..D0]; MulDiv: PROCEDURE [a,b,c:CARDINAL] RETURNS [CARDINAL] = INLINE BEGIN al: LONG CARDINAL _ InlineDefs.LongMult[a,b]; RETURN[InlineDefs.LongDiv[al,c]]; END; HalftoneParams: TYPE = MACHINE DEPENDENT RECORD [ nInputPixels: CARDINAL, black: INTEGER, range: INTEGER, nOutputDots: CARDINAL, errorVec: LONG POINTER, bitmap: LONG POINTER, bitOffset: CARDINAL, mode: [0..17B], xOdd: BOOLEAN, bitmapWidth: [0..3777B], pixelArray: LONG POINTER, wordAlignPad: ARRAY [0..3) OF UNSPECIFIED ]; errorVec: POINTER TO ARRAY [0..0) OF INTEGER _ NIL; hp: HalftoneParams; off: CARDINAL _ SELECT InlineDefs.BITAND[@hp,3] FROM 0=>0,1=>3,2=>2,ENDCASE=>1; halftoneParams: POINTER TO HalftoneParams _ LOOPHOLE[@hp+off]; yctr: INTEGER; lineCount: INTEGER; yInc,yDec: CARDINAL; yLimit: INTEGER; xMin: CARDINAL; --for soft version, we also need: BitTable: ARRAY [0..20B) OF CARDINAL _ [100000B,40000B,20000B,10000B,4000B,2000B, 1000B,400B,200B,100B,40B,20B,10B,4,2,1 ]; outputPixelArray,errorArray: POINTER TO ARRAY [0..256) OF CARDINAL _ NIL; nBitsPerPixel: CARDINAL _ 0;--comes from bitmap.nBitsPerPixel outputBitsPerPixel: CARDINAL _ 1; colorShift: CARDINAL _ 0; fieldLen: CARDINAL _ 1; UseError: BOOLEAN _ TRUE; DistributeError: BOOLEAN _ TRUE; SetHalftoneResolution: PUBLIC PROCEDURE [nOutputBitsPerPixel,fieldLength,nOffsetBits: CARDINAL,useError: BOOLEAN _ TRUE,distributeError: BOOLEAN _ TRUE] = BEGIN IF nBitsPerPixel = 0 THEN nBitsPerPixel _ GetDefaultBitmapHandle[].nBitsPerPixel; outputBitsPerPixel _ nOutputBitsPerPixel; colorShift _ (16-nBitsPerPixel)+nOffsetBits; fieldLen _ fieldLength; UseError _ useError; DistributeError _ useError AND distributeError; END; MakeLongPointer: PUBLIC PROCEDURE [ptr: POINTER,bank: UNSPECIFIED] RETURNS [LONG POINTER] = MACHINE CODE BEGIN END; InitHalftone: PUBLIC PROCEDURE [ x,y: CARDINAL, --top left corner in bitmap nInputPixels,nOutputDots: CARDINAL, --8 bit pixels, packed black: INTEGER _ 0,white: INTEGER _ 255, bitmap: POINTER TO Bitmap _ NIL, nInputLines: CARDINAL _ 0,nOutputLines: CARDINAL _ 0, mode: CARDINAL _ 3] = BEGIN bMode: CARDINAL _ mode/4; --bit direction mode sMode: CARDINAL _ mode MOD 4; --scan direction mode dotMax,xLimit: CARDINAL; initVal: INTEGER _ ((black-white)*3-4)/8; IF initVal > 0 THEN initVal _ -MulDiv[white-black,3,8]; --overflow IF bitmap = NIL THEN bitmap _ GetDefaultBitmapHandle[]; nBitsPerPixel _ bitmap.nBitsPerPixel; IF nBitsPerPixel > 1 THEN initVal _ 0; SELECT bMode FROM 0,1 => BEGIN dotMax _ x+nOutputDots-1; xLimit _ bitmap.nBits-1; END; ENDCASE => BEGIN dotMax _ y+nOutputDots-1; xLimit _ bitmap.nLines-1; END; IF errorVec # NIL THEN SystemDefs.FreeSegment[errorVec]; errorVec _ SystemDefs.AllocateSegment[x+nOutputDots]; xMin _ 0; IF nInputLines = 0 THEN BEGIN IF bMode IN [2..3] THEN ERROR; --can't default nInputLines _ nInputPixels; nOutputLines _ nOutputDots; END; IF INTEGER[x] < 0 THEN ERROR; IF dotMax > xLimit THEN BEGIN nP: CARDINAL _ MulDiv[nInputPixels,nOutputDots-(dotMax-xLimit),nOutputDots]; nOutputDots _ MulDiv[nOutputDots,nP,nInputPixels]; IF bMode IN [1..2] THEN xMin _ nInputPixels-nP; nInputPixels _ nP; END; halftoneParams^ _ [ nInputPixels: nInputPixels,black: black,range: white-black, nOutputDots: nOutputDots, errorVec: MakeLongPointer[errorVec,0], bitmap: MakeLongPointer[bitmap.bits,bitmap.bank]+LONG[y]*bitmap.nWords + (SELECT sMode FROM 0 => LONG[x/16], 1 => LONG[(x+nOutputLines-1)/16], 2=> LONG[nOutputLines-1]*bitmap.nWords, ENDCASE => 0) + (SELECT bMode FROM 2 => LONG[nOutputDots-1]*bitmap.nWords, ENDCASE =>0), bitOffset: x + (SELECT TRUE FROM bMode=1 => nOutputDots-1, sMode=1 => nOutputLines-1, ENDCASE => 0), mode: mode,xOdd: (xMin MOD 2) = 1,bitmapWidth: bitmap.nWords, pixelArray: ,wordAlignPad: ]; IF machine = AltoIIXM THEN BEGIN UseMicrocode_TRUE; AltoMicrocodeDefs.LoadRam[]; --nop after first call --check for illegal long pointers IF (InlineDefs.HighHalf[halftoneParams.errorVec] # 0) THEN ERROR; IF (halftoneParams.mode # 3) THEN UseMicrocode_FALSE; END; lineCount _ SELECT sMode FROM 2=>y+nOutputLines-1,0=>x,1=>x+nOutputLines-1,ENDCASE=>y; yLimit _ SELECT bMode FROM 2,3=>bitmap.nBits-1,ENDCASE=>bitmap.nLines-1; yInc _ nInputLines; yDec _ nOutputLines; yctr _ -nOutputLines; MiscDefs.SetBlock[errorVec,initVal,x+nOutputDots]; IF nBitsPerPixel > 1 THEN BEGIN maxVal: CARDINAL = SELECT outputBitsPerPixel FROM 1=>1,2=>3,3=>7,4=>15,5=>31,6=>63,7=>127,ENDCASE=>255; maxVal2: CARDINAL = maxVal*2; fieldMultiplier: CARDINAL = SELECT fieldLen FROM 1=>1,2=>3,3=>7,4=>15,5=>31,6=>63,7=>127,ENDCASE=>255; bucket: CARDINAL _ 0; i: CARDINAL; IF outputPixelArray = NIL THEN BEGIN outputPixelArray _ SystemDefs.AllocateSegment[256]; errorArray _ SystemDefs.AllocateSegment[256]; END; IF outputBitsPerPixel = 8 THEN FOR i IN [0..256) DO outputPixelArray[i] _ i; errorArray[i] _ 0; ENDLOOP ELSE UNTIL bucket = maxVal2 DO FOR i IN [(256*bucket)/maxVal2..(256*(bucket+1))/maxVal2) DO outputPixelArray[i] _ ((bucket/2)*fieldMultiplier)/maxVal; errorArray[i] _ i-(256*bucket)/maxVal2; ENDLOOP; bucket _ bucket+1; FOR i IN [(256*bucket)/maxVal2..(256*(bucket+1))/maxVal2) DO outputPixelArray[i] _ (((bucket+1)/2)*fieldMultiplier)/maxVal; errorArray[i] _ i-(256*(bucket+1))/maxVal2; ENDLOOP; bucket _ bucket+1; ENDLOOP; END; END; PrintHalftoneLine: PUBLIC PROCEDURE [p: LONG POINTER TO ARRAY [0..0) OF UNSPECIFIED] RETURNS [nLinesPrinted: CARDINAL] = BEGIN firstLineCount: INTEGER _ lineCount; bMode: CARDINAL _ halftoneParams.mode/4; --bit direction mode sMode: CARDINAL _ halftoneParams.mode MOD 4; --scan direction mode IF outputBitsPerPixel = 0 THEN RETURN; halftoneParams.pixelArray _ p+xMin/2; IF machine NOT IN [D0..Dorado] THEN IF InlineDefs.HighHalf[p] # 0 THEN ERROR; WHILE yctr < 0 DO IF lineCount IN [0..yLimit] THEN IF nBitsPerPixel = 1 THEN IF UseMicrocode THEN IF machine = D0 THEN [] _ D0MicrocodeDefs.JumpRamArgRslt[htMicrocodeStart,halftoneParams] ELSE AltoMicrocodeDefs.PrintHalftoneLine[halftoneParams] ELSE SoftPrintLine1[p] ELSE SoftPrintLineN[p]; yctr _ yctr + yInc; halftoneParams.bitOffset _ halftoneParams.bitOffset + (SELECT sMode FROM 0 => 1, 1 => -1, ENDCASE => 0); halftoneParams.bitmap _ halftoneParams.bitmap + (SELECT sMode FROM 0 => IF halftoneParams.bitOffset MOD 16 = 0 THEN 1 ELSE 0, 1 => IF halftoneParams.bitOffset MOD 16 = 15 THEN -1 ELSE 0, 2 => -halftoneParams.bitmapWidth, ENDCASE => halftoneParams.bitmapWidth); lineCount _ lineCount + (SELECT sMode FROM 1,2 => -1, ENDCASE => 1); ENDLOOP; -- while yctr < 0 yctr _ yctr - yDec; RETURN[ABS[lineCount-firstLineCount]]; END; SoftPrintLine1: PROCEDURE [p: LONG POINTER TO ARRAY [0..0) OF UNSPECIFIED] = BEGIN OPEN InlineDefs; x: CARDINAL; val: INTEGER; error,error1: INTEGER; bMode: CARDINAL _ halftoneParams.mode/4; pixelArray: LONG POINTER TO PACKED ARRAY OF [0..377B] _ LOOPHOLE[p]; screenWord: LONG POINTER TO ARRAY [0..0) OF CARDINAL _ halftoneParams.bitmap; bitmapWidth: CARDINAL _ halftoneParams.bitmapWidth; bitCount: CARDINAL _ SELECT bMode FROM 2,3 => 0,ENDCASE => halftoneParams.bitOffset; bit: CARDINAL _ BitTable[halftoneParams.bitOffset MOD 16]; CascadeDiag: INTEGER _ 0; CascadeRight: INTEGER _ errorVec[bitCount]*(IF bMode<2 THEN 4 ELSE 2)-1; jctr: INTEGER _ -halftoneParams.nOutputDots; s: CARDINAL; IF machine IN [D0..Dorado] THEN FOR x IN [xMin..xMin+halftoneParams.nInputPixels) DO val _ MIN[MAX[0,pixelArray[x]-halftoneParams.black],halftoneParams.range]; WHILE jctr < 0 DO error _ CascadeRight+val; IF error < 0 THEN --print black BEGIN SELECT bMode FROM 2,3 => --Bottom to Top or Bottom to Top screenWord[0] _ InlineDefs.BITOR[screenWord[0],bit]; ENDCASE => --Left to Right or Right to Left screenWord[bitCount/16] _ InlineDefs.BITOR[screenWord[bitCount/16],BitTable[bitCount MOD 16]]; END ELSE error _ error-halftoneParams.range; s_BITAND[error,100000B]; SELECT InlineDefs.BITAND[error,3] FROM 0=>BEGIN error _ BITSHIFT[error,-1]+s; error1 _ BITSHIFT[error,-1]+s;END; 1=>BEGIN error _ BITSHIFT[error,-1]+s; error1 _ BITSHIFT[error,-1]+s;error _ error+1;END; 2=>BEGIN error _ BITSHIFT[error,-1]+s; error1 _ BITSHIFT[error,-1]+s;error _ error+1;END; ENDCASE=>BEGIN error _ BITSHIFT[error,-1]+s; error1 _ BITSHIFT[error,-1]+s+1;END; IF bMode < 2 THEN errorVec[bitCount] _ CascadeDiag+error1 ELSE errorVec[bitCount] _ CascadeDiag+error; CascadeDiag_error1; bitCount _ bitCount+1; --right 3/4 of the time SELECT bMode FROM 2 => --Bottom to Top screenWord _ screenWord-halftoneParams.bitmapWidth; 1 => --Right to Left bitCount _ bitCount-2; 3 => --Top to Bottom screenWord _ screenWord+halftoneParams.bitmapWidth; ENDCASE; --normal=Left to Right, Top to Bottom CascadeRight _ errorVec[bitCount]+(IF bMode < 2 THEN error ELSE error1); jctr _ jctr + halftoneParams.nInputPixels; ENDLOOP; --while jctr < 0 jctr _ jctr - halftoneParams.nOutputDots; ENDLOOP --FOR x ELSE --Alto, long pointers die BEGIN p: POINTER TO PACKED ARRAY OF [0..377B] _ InlineDefs.LowHalf[pixelArray]; sw: POINTER TO ARRAY [0..0) OF CARDINAL _ InlineDefs.LowHalf[screenWord]; FOR x IN [xMin..xMin+halftoneParams.nInputPixels) DO val _ MIN[MAX[0,p[x]-halftoneParams.black],halftoneParams.range]; WHILE jctr < 0 DO error _ CascadeRight+val; IF error < 0 THEN --print black BEGIN OPEN LongDefs; SELECT bMode FROM 2,3 => --Bottom to Top or Bottom to Top AltoWrite[addr: screenWord, val: InlineDefs.BITOR[AltoRead[screenWord],bit]]; ENDCASE => --Left to Right or Right to Left AltoWrite[addr: screenWord+bitCount/16, val: InlineDefs.BITOR[AltoRead[screenWord+bitCount/16], BitTable[bitCount MOD 16]]]; END ELSE error _ error-halftoneParams.range; s_BITAND[error,100000B]; SELECT InlineDefs.BITAND[error,3] FROM 0=>BEGIN error _ BITSHIFT[error,-1]+s; error1 _ BITSHIFT[error,-1]+s;END; 1=>BEGIN error _ BITSHIFT[error,-1]+s; error1 _ BITSHIFT[error,-1]+s;error _ error+1;END; 2=>BEGIN error _ BITSHIFT[error,-1]+s; error1 _ BITSHIFT[error,-1]+s;error _ error+1;END; ENDCASE=>BEGIN error _ BITSHIFT[error,-1]+s; error1 _ BITSHIFT[error,-1]+s+1;END; IF bMode < 2 THEN errorVec[bitCount] _ CascadeDiag+error1 ELSE errorVec[bitCount] _ CascadeDiag+error; CascadeDiag_error1; bitCount _ bitCount+1; --right 3/4 of the time SELECT bMode FROM 2 => --Bottom to Top screenWord _ screenWord-halftoneParams.bitmapWidth; 1 => --Right to Left bitCount _ bitCount-2; 3 => --Top to Bottom screenWord _ screenWord+halftoneParams.bitmapWidth; ENDCASE; --normal=Left to Right, Top to Bottom CascadeRight _ errorVec[bitCount]+(IF bMode < 2 THEN error ELSE error1); jctr _ jctr + halftoneParams.nInputPixels; ENDLOOP; --while jctr < 0 jctr _ jctr - halftoneParams.nOutputDots; ENDLOOP; --FOR x END; END; SoftPrintLineN: PROCEDURE [p: LONG POINTER TO ARRAY [0..0) OF UNSPECIFIED] = BEGIN OPEN InlineDefs; x: CARDINAL; val,error,pixelIndex,pixelVal: INTEGER; prevError4: INTEGER _ 0; bMode: CARDINAL _ halftoneParams.mode/4; pixelArray: LONG POINTER TO PACKED ARRAY OF [0..377B] _ LOOPHOLE[p]; screenWord: LONG POINTER TO ARRAY [0..0) OF CARDINAL _ halftoneParams.bitmap; bitmapWidth: CARDINAL _ halftoneParams.bitmapWidth; bitCount: CARDINAL _ SELECT bMode FROM 2,3 => 0,ENDCASE => (halftoneParams.bitOffset)*nBitsPerPixel; jctr: INTEGER _ -halftoneParams.nOutputDots; firstBit: CARDINAL _ (halftoneParams.bitOffset*nBitsPerPixel) MOD 16; shift: CARDINAL _ colorShift-firstBit; CascadeDiag: INTEGER _ 0; error _ 0; FOR x IN [xMin..xMin+halftoneParams.nInputPixels) DO val _ MIN[MAX[0,pixelArray[x]-halftoneParams.black],halftoneParams.range]; WHILE jctr < 0 DO pixelIndex _ val+error; SELECT pixelIndex FROM <0 => BEGIN pixelVal _ outputPixelArray[0]; IF UseError THEN error _ pixelIndex; END; IN [0..256) => BEGIN pixelVal _ outputPixelArray[pixelIndex]; IF UseError THEN error _ errorArray[pixelIndex]; END; ENDCASE => BEGIN pixelVal _ outputPixelArray[255]; IF UseError THEN error _ pixelIndex-halftoneParams.range; END; SELECT bMode FROM 2,3 => --Bottom to Top or Bottom to Top screenWord[0] _ BITOR[screenWord[0],BITSHIFT[pixelVal,shift]]; ENDCASE => --Left to Right or Right to Left screenWord[bitCount/16] _ BITOR[screenWord[bitCount/16], BITSHIFT[pixelVal,colorShift-(bitCount MOD 16)]]; IF DistributeError THEN BEGIN s: CARDINAL _ BITAND[error,100000B]; currentError4: INTEGER; SELECT InlineDefs.BITAND[error,3] FROM 0=>BEGIN error _ BITSHIFT[error,-1]+s; currentError4 _ BITSHIFT[error,-1]+s;END; 1=>BEGIN error _ BITSHIFT[error,-1]+s; currentError4 _ BITSHIFT[error,-1]+s;error _ error+1;END; 2=>BEGIN error _ BITSHIFT[error,-1]+s; currentError4 _ BITSHIFT[error,-1]+s;error _ error+1;END; ENDCASE=>BEGIN error _ BITSHIFT[error,-1]+s; currentError4 _ BITSHIFT[error,-1]+s+1;END; errorVec[bitCount/nBitsPerPixel] _ prevError4+currentError4; prevError4 _ currentError4; END; bitCount _ bitCount+nBitsPerPixel; --right 3/4 of the time SELECT bMode FROM 2 => --Bottom to Top screenWord _ screenWord-halftoneParams.bitmapWidth; 1 => --Right to Left bitCount _ bitCount-2*nBitsPerPixel; 3 => --Top to Bottom screenWord _ screenWord+halftoneParams.bitmapWidth; ENDCASE; --normal=Left to Right, Top to Bottom IF DistributeError THEN error _ errorVec[bitCount/nBitsPerPixel]+error; jctr _ jctr + halftoneParams.nInputPixels; ENDLOOP; --while jctr < 0 jctr _ jctr - halftoneParams.nOutputDots; ENDLOOP; --FOR x END; END. (635)\f1