-- HalftoneImpl.mesa -- Written by Joe Maleson -- Last changed by Doug Wyatt, October 20, 1980 2:38 PM --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, LongDefs,-- GraphicsDefs, InlineDefs, SegmentDefs, MiscDefs, SystemDefs EXPORTS HalftoneDefs = BEGIN OPEN HalftoneDefs, GraphicsDefs, MiscDefs; machine: SegmentDefs.MachineType _ SegmentDefs.GetMemoryConfig[].AltoType; UseMicrocode: BOOLEAN = FALSE; -- machine IN [AltoIIXM..D0]; -- DKW: All microcode disabled. 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 SoftPrintLine1[p] -- DKW: Don't use microcode -- 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 -- DKW: For now, this is a noop on Alto --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. e6(635)\f1 835b9B11b15B11b128B150b1B806b301B410b15B102b12B2020b91f0 2f1 22f0 2f1 163B1700b79B163b23B2b3B64b7B2b55B638b14B683b32B1650b31B5f0 43f1 74f0 3f1 74f0 3f1 52f0 3f1 66f0 3f1 18f0 3f1 27f0 3f1 20f0 2f1 11f0 3f1 23f0 3f1 20f0 3f1 11f0 2f1 30f0 3f1 32f0 3f1 55f0 3f1 15f0 2f1 30f0 3f1 44f0 3f1 61f0 3f1 36f0 3f1 6f0 3f1 42f0 3f1 26f0 3f1 40f0 3f1 41f0 3f1 38f0 3f1 41f0 3f1 54f0 3f1 41f0 3f1 54f0 3f1 47f0 3f1 40f0 3f1 59f0 3f1 46f0 3f1 21f0 3f1 25f0 2f1 21f0 3f1 19f0 3f1 8f0 2f1 13f0 3f1 55f0 3f1 8f0 2f1 13f0 3f1 26f0 3f1 8f0 2f1 13f0 3f1 55f0 3f1 12f0 2f1 35f0 3f1 74f0 3f1 44f0 3f1 10f0 2f1 14f0 3f1 42f0 3f1 9f0 2f1 5f0 1f1 4f0 1f1 5b15B493b14B