--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], MemoryOps: FROM "MemoryOps" USING [GetMemoryConfig,MachineType], MiscDefs: FROM "MiscDefs" USING [SetBlock], SystemDefs: FROM "SystemDefs"; HalftoneImpl: PROGRAM IMPORTS AltoMicrocodeDefs, D0MicrocodeDefs, GraphicsDefs, InlineDefs, MemoryOps, MiscDefs, SystemDefs EXPORTS HalftoneDefs = BEGIN OPEN HalftoneDefs, GraphicsDefs, MiscDefs; machine: MemoryOps.MachineType _ MemoryOps.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) OR (InlineDefs.HighHalf[halftoneParams.bitmap] # 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[7000B,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 SELECT bMode FROM 2,3 => --Bottom to Top or Bottom to Top sw[0] _ InlineDefs.BITOR[sw[0],bit]; ENDCASE => --Left to Right or Right to Left sw[bitCount/16] _ InlineDefs.BITOR[sw[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 sw _ sw-halftoneParams.bitmapWidth; 1 => --Right to Left bitCount _ bitCount-2; 3 => --Top to Bottom sw _ sw+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. e6(635)\f1 702b128B150b1B806b301B410b15B102b12B2020b325B1700b79B110b26B62b62B636b14B683b32B1649b31B1743b15B493b14B601f0 5f1 471f0 3f1 23f0 3f1 6f0 3f1 37f0 3f1 1f0 13f1 10f0 3f1 39f0 3f1 40f0 3f1 3f0 13f1 28f0 3f1 40f0 3f1 3f0 13f1 44f0 3f1 40f0 3f1 3f0 13f1 44f0 3f1 46f0 3f1 3f0 13f1 30f0 3f1 47f0 13f1 1f0 3f1 14f0 13f1 1f0 3f1