<> <> <> <> DIRECTORY Basics USING [BITSHIFT, bitsPerWord, BYTE, LongMult], ImagerColorDefs USING [Color, ColorOperator, ConstantColor, ConstantColorImplRep, SampledColor], ImagerColorOperator USING [GetColorOperatorClass, Mapper, MapPixels, NewMapper], ImagerColorPrivate USING [ConstantColorImpl, ConstantColorImplRep], ImagerDevice USING [BoxProc, Class, ClassRep, Device, DeviceBox, DeviceRep, HalftoneParameters, RunProc], ImagerMask USING [RunsFromBits, RunsFromBox], ImagerPixelArray USING [GetPixels, MaxSampleValue], ImagerPixelArrayDefs USING [PixelArray], ImagerPixelMap USING [PixelMap, Reshape], ImagerRaster USING [], ImagerSample USING [BitsPerSample, GetPointer, GetPointSamples, NewBuffer, Sample, SampleBuffer, Sampler, SamplerRep, SetSamplerIncrements, SetSamplerPosition, UnsafePutF, UnsafeSamples], ImagerTransformation USING [ApplyPreRotate, Cat, Transformation, Translate], PrincOps USING [BBTableSpace, BitAddress, BitBltFlags, BitBltTable, BitBltTablePtr, GrayParm, op, zBNDCK, zINC], PrincOpsUtils USING [AlignedBBTable, BITBLT], Real USING [RoundC], Terminal USING [FrameBuffer, GetColorFrameBufferA, ModifyColorFrame, Virtual], Vector2 USING [VEC]; ImagerGrayDeviceImpl: CEDAR PROGRAM IMPORTS Basics, ImagerColorOperator, ImagerMask, ImagerPixelArray, ImagerPixelMap, ImagerSample, ImagerTransformation, PrincOpsUtils, Real, Terminal EXPORTS ImagerColorDefs, ImagerRaster ~ BEGIN OPEN ImagerDevice; BYTE: TYPE ~ Basics.BYTE; VEC: TYPE ~ Vector2.VEC; Transformation: TYPE ~ ImagerTransformation.Transformation; Color: TYPE ~ ImagerColorDefs.Color; ConstantColor: TYPE ~ ImagerColorDefs.ConstantColor; SampledColor: TYPE ~ ImagerColorDefs.SampledColor; ColorOperator: TYPE ~ ImagerColorDefs.ColorOperator; PixelArray: TYPE ~ ImagerPixelArrayDefs.PixelArray; Sample: TYPE ~ ImagerSample.Sample; SampleBuffer: TYPE ~ ImagerSample.SampleBuffer; UnsafeSamples: TYPE ~ ImagerSample.UnsafeSamples; ConstantColorImpl: TYPE ~ ImagerColorPrivate.ConstantColorImpl; ConstantColorImplRep: PUBLIC TYPE ~ ImagerColorPrivate.ConstantColorImplRep; Case: TYPE ~ {nil, constant, stipple, sampled}; StippleArray: TYPE ~ PACKED ARRAY [0..16) OF BYTE; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD[ terminal: Terminal.Virtual, frame: Terminal.FrameBuffer, -- the frame buffer case: Case _ nil, -- what type of color sampledBlack: BOOL _ FALSE, sampledBlackClear: BOOL _ FALSE, bitsPerPixel: ImagerSample.BitsPerSample _ 0, flags: PrincOps.BitBltFlags _ [], -- bitblt flags grayWord: WORD _ 0, -- constant gray word (two pixels) stipple: StippleArray _ ALL[0], -- stipple pattern sampledColor: SampledColor _ NIL, -- sampled color paToDevice: Transformation _ NIL, -- transformation from pa coords to display source: ImagerPixelMap.PixelMap _ [0, 0, 0, 0, 0, 0, NIL], -- source values from pixel array sampler: ImagerSample.Sampler _ NIL, -- sampler information buffer: ImagerSample.SampleBuffer _ NIL -- scan line buffer for samples ]; class: ImagerDevice.Class ~ NEW[ImagerDevice.ClassRep _ [ type: $GrayDisplay, SetColor: GraySetColor, SetPriority: GraySetPriority, SetHalftone: GraySetHalftone, MaskRuns: GrayMaskRuns, MaskBoxes: GrayMaskBoxes, MaskBits: GrayMaskBits, MoveBoxes: GrayMoveBoxes ]]; <> <> <<>> NewGrayDevice: PUBLIC PROC[terminal: Terminal.Virtual] RETURNS[Device] ~ { frame: Terminal.FrameBuffer ~ Terminal.GetColorFrameBufferA[terminal]; IF frame=NIL OR frame.bitsPerPixel#8 THEN RETURN[NIL] ELSE { data: Data ~ NEW[DataRep _ [terminal: terminal, frame: frame]]; pixelsPerInch: REAL ~ terminal.colorPixelsPerInch; surfaceToDevice: Transformation ~ ImagerTransformation.Translate[[frame.height, 0]]; surfaceToDevice.ApplyPreRotate[90]; RETURN[NEW[ImagerDevice.DeviceRep _ [class: class, box: [smin: 0, fmin: 0, smax: frame.height, fmax: frame.width], surfaceToDevice: surfaceToDevice, surfaceUnitsPerInch: [pixelsPerInch, pixelsPerInch], surfaceUnitsPerPixel: 1, data: data]]]; }; }; nullBitBltTable: PrincOps.BitBltTable ~ [ dst: [word: NIL, bit: 0], dstBpl: 0, src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]], width: 0, height: 0, flags: [] ]; bitsPerPixel: NAT ~ 8; bitsPerWord: NAT ~ Basics.bitsPerWord; StippleArrayFromWord: PROC[t: WORD] RETURNS[array: StippleArray _ ALL[0]] ~ { bits: PACKED ARRAY [0..16) OF BOOL ~ LOOPHOLE[t]; FOR i: [0..16) IN [0..16) DO IF bits[i] THEN array[i] _ BYTE.LAST ENDLOOP; }; PixelFromIntensity: PROC[Y: REAL] RETURNS[BYTE] ~ { IF Y<=0 THEN RETURN[0]; -- black IF Y>=1 THEN RETURN[BYTE.LAST]; -- white RETURN[Real.RoundC[Y*BYTE.LAST]]; -- gray }; sourceLgBitsPerSample: NAT ~ 3; -- for array of samples from sampled color sourceBitsPerSample: NAT ~ Basics.BITSHIFT[1, sourceLgBitsPerSample]; maxSourceSample: Sample ~ Basics.BITSHIFT[1, sourceBitsPerSample]-1; GraySetColor: PROC[device: Device, color: Color, viewToDevice: Transformation] ~ { data: Data ~ NARROW[device.data]; WITH color SELECT FROM color: ConstantColor => { impl: ConstantColorImpl ~ color.impl; data.case _ constant; data.source.refRep _ NIL; data.flags _ [disjoint: TRUE, gray: TRUE, srcFunc: null, dstFunc: null]; WITH impl: impl SELECT FROM stipple => { word: WORD ~ impl.word; SELECT impl.function FROM replace => { data.flags.srcFunc _ complement }; paint => { data.flags.srcFunc _ complement; data.flags.dstFunc _ and }; invert => { data.flags.dstFunc _ xor }; erase => { data.flags.dstFunc _ or }; ENDCASE => ERROR; IF word=WORD.LAST THEN data.grayWord _ word ELSE { data.stipple _ StippleArrayFromWord[word]; data.case _ stipple }; }; ENDCASE => { pixel: BYTE ~ PixelFromIntensity[impl.Y]; data.grayWord _ pixel*400B+pixel; }; }; color: SampledColor => { pa: PixelArray ~ color.pa; um: Transformation ~ color.um; colorOperator: ColorOperator ~ color.colorOperator; samplesPerPixel: NAT ~ pa.samplesPerPixel; sSize: NAT ~ pa.sSize; fSize: NAT ~ pa.fSize; maxIn: Sample ~ ImagerPixelArray.MaxSampleValue[pa, 0]; source: ImagerPixelMap.PixelMap ~ data.source.refRep.Reshape[ lgBitsPerPixel: sourceLgBitsPerSample, bounds: [sMin: 0, fMin: 0, sSize: sSize, fSize: fSize]]; sourceBase: LONG POINTER ~ source.refRep.pointer; sourceWordsPerLine: NAT ~ source.refRep.rast; pixels: SampleBuffer ~ ImagerSample.NewBuffer[samplesPerPixel, fSize]; buffer: SampleBuffer ~ ImagerSample.NewBuffer[1, fSize]; mapper: ImagerColorOperator.Mapper ~ ImagerColorOperator.NewMapper[ op: colorOperator, component: $Intensity, maxIn: maxIn, maxOut: maxSourceSample]; samples: UnsafeSamples ~ buffer.GetPointer[0, 0, fSize]; FOR s: NAT IN[0..sSize) DO ImagerPixelArray.GetPixels[pa: pa, s: s, f: 0, buffer: pixels, count: fSize]; ImagerColorOperator.MapPixels[mapper: mapper, pixels: pixels, buffer: buffer, count: fSize]; TRUSTED { ImagerSample.UnsafePutF[samples: samples, count: fSize, base: sourceBase, wordsPerLine: sourceWordsPerLine, bitsPerSample: sourceBitsPerSample, s: s, f: 0] }; ENDLOOP; data.sampledColor _ color; data.paToDevice _ ImagerTransformation.Cat[pa.m, color.um, viewToDevice]; data.source _ source; IF data.sampler=NIL THEN data.sampler _ NEW[ImagerSample.SamplerRep _ []]; data.sampler.base _ sourceBase; data.sampler.wordsPerLine _ sourceWordsPerLine; data.sampler.bitsPerSample _ sourceBitsPerSample; data.sampler.sMin _ source.sMin; data.sampler.fMin _ source.fMin; data.sampler.sSize _ source.sSize; data.sampler.fSize _ source.fSize; ImagerSample.SetSamplerIncrements[data.sampler, data.paToDevice]; IF data.buffer=NIL THEN data.buffer _ ImagerSample.NewBuffer[1, data.frame.width]; SELECT ImagerColorOperator.GetColorOperatorClass[colorOperator] FROM $SampledBlack => {data.sampledBlack _ TRUE; data.sampledBlackClear _ FALSE}; $SampledBlackClear => {data.sampledBlack _ data.sampledBlackClear _ TRUE}; ENDCASE => data.sampledBlack _ data.sampledBlackClear _ FALSE; data.case _ sampled; }; ENDCASE => ERROR; -- unknown color variant }; GraySetPriority: PROC[device: Device, priorityImportant: BOOL] ~ { }; GraySetHalftone: PROC[device: Device, halftone: HalftoneParameters] ~ { data: Data ~ NARROW[device.data]; <> }; Check: PROC[x: CARDINAL, max: NAT] RETURNS[NAT] ~ TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK }; <> GrayMaskRunsInternal: PROC[data: Data, bounds: DeviceBox, runs: PROC[RunProc]] ~ { frame: Terminal.FrameBuffer ~ data.frame; base: LONG POINTER ~ frame.base; wordsPerLine: NAT ~ frame.wordsPerLine; SELECT data.case FROM nil => ERROR; -- color not initialized constant => TRUSTED { bbspace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace]; grayConstantRun: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED { f: NAT ~ Check[fMin, frame.width]; s: NAT ~ Check[sMin, frame.height]; line: LONG POINTER ~ base+Basics.LongMult[s, wordsPerLine]; bit: CARDINAL ~ f*bitsPerPixel; bb.dst.word _ line+bit/bitsPerWord; bb.dst.bit _ bit MOD bitsPerWord; bb.width _ Check[fSize, frame.width-f]*bitsPerPixel; bb.height _ Check[1, frame.height-s]; PrincOpsUtils.BITBLT[bb]; }; bb^ _ nullBitBltTable; bb.dstBpl _ wordsPerLine*bitsPerWord; bb.src.word _ LOOPHOLE[@data.grayWord]; bb.srcDesc.gray _ [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]; bb.flags _ data.flags; runs[grayConstantRun]; }; stipple => TRUSTED { bbspace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace]; srcBase: LONG POINTER ~ LOOPHOLE[@data.stipple]; srcWordsPerLine: NAT ~ (4*bitsPerPixel)/bitsPerWord; grayStippleRun: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED { fmin: NAT ~ Check[fMin, frame.width]; fmax: NAT ~ Check[fmin+fSize, frame.width]; smin: NAT ~ Check[sMin, frame.height]; smax: NAT ~ Check[smin+1, frame.height]; dstLine: LONG POINTER ~ base+Basics.LongMult[smin, wordsPerLine]; srcLine: LONG POINTER ~ srcBase+(smin MOD 4)*srcWordsPerLine; FOR f: NAT IN [fmin..MIN[fmin+4, fmax]) DO dstBit: NAT ~ f*bitsPerPixel; srcBit: NAT ~ (f MOD 4)*bitsPerPixel; bb.dst.word _ dstLine+dstBit/bitsPerWord; bb.dst.bit _ dstBit MOD bitsPerWord; bb.src.word _ srcLine+srcBit/bitsPerWord; bb.src.bit _ srcBit MOD bitsPerWord; bb.height _ (fmax-f+3)/4; PrincOpsUtils.BITBLT[bb]; ENDLOOP; }; bb^ _ nullBitBltTable; bb.dstBpl _ 4*bitsPerPixel; bb.srcDesc.gray _ [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]; bb.width _ bitsPerPixel; bb.flags _ data.flags; runs[grayStippleRun]; }; sampled => { sampler: ImagerSample.Sampler ~ data.sampler; buffer: SampleBuffer ~ data.buffer; graySampledRun: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ CHECKED { s: NAT ~ Check[sMin, frame.height]; f: NAT ~ Check[fMin, frame.width]; count: NAT ~ Check[fSize, frame.width-f]; samples: ImagerSample.UnsafeSamples ~ buffer.GetPointer[0, f, count]; ImagerSample.GetPointSamples[sampler: sampler, s: s, f: f, buffer: buffer, bi: 0, bj: f, count: count]; TRUSTED { ImagerSample.UnsafePutF[samples: samples, count: count, base: base, wordsPerLine: wordsPerLine, bitsPerSample: 8, s: s, f: f, dstFunc: IF data.sampledBlackClear THEN and ELSE null]}; }; ImagerSample.SetSamplerPosition[sampler: sampler, m: data.paToDevice, s: bounds.smin, f: bounds.fmin]; runs[graySampledRun]; }; ENDCASE => ERROR; -- illegal case }; GrayMaskBoxesInternal: PROC[data: Data, bounds: DeviceBox, boxes: PROC[BoxProc]] ~ { IF data.case=constant THEN TRUSTED { frame: Terminal.FrameBuffer ~ data.frame; base: LONG POINTER ~ frame.base; wordsPerLine: NAT ~ frame.wordsPerLine; bbspace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace]; grayConstantBox: PROC[box: DeviceBox] ~ TRUSTED { fmin: NAT ~ Check[box.fmin, frame.width]; fmax: NAT ~ Check[box.fmax, frame.width]; smin: NAT ~ Check[box.smin, frame.height]; smax: NAT ~ Check[box.smax, frame.height]; line: LONG POINTER ~ base+Basics.LongMult[smin, wordsPerLine]; bit: NAT ~ fmin*bitsPerPixel; bb.dst.word _ line+bit/bitsPerWord; bb.dst.bit _ bit MOD bitsPerWord; bb.width _ (fmax-fmin)*bitsPerPixel; bb.height _ smax-smin; PrincOpsUtils.BITBLT[bb]; }; bb^ _ nullBitBltTable; bb.dstBpl _ wordsPerLine*bitsPerWord; bb.src.word _ LOOPHOLE[@data.grayWord]; bb.srcDesc.gray _ [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]; bb.flags _ data.flags; boxes[grayConstantBox]; } ELSE { grayNonConstantBox: PROC[box: DeviceBox] ~ { runs: PROC[run: RunProc] ~ { ImagerMask.RunsFromBox[box: box, run: run] }; GrayMaskRunsInternal[data: data, bounds: box, runs: runs]; }; boxes[grayNonConstantBox]; }; }; ModifyColorFrame: PROC [vt: Terminal.Virtual, action: PROC, xmin: NAT, ymin: NAT, xmax: NAT, ymax: NAT] ~ INLINE { IF vt = NIL THEN action[] ELSE Terminal.ModifyColorFrame[vt: vt, action: action, xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax]; }; GrayMaskRuns: PROC[device: Device, bounds: DeviceBox, runs: PROC[RunProc]] ~ { data: Data ~ NARROW[device.data]; grayMaskRunsAction: PROC ~ { GrayMaskRunsInternal[data, bounds, runs] }; ModifyColorFrame[vt: data.terminal, action: grayMaskRunsAction, xmin: bounds.fmin, ymin: bounds.smin, xmax: bounds.fmax, ymax: bounds.smax]; }; GrayMaskBoxes: PROC[device: Device, bounds: DeviceBox, boxes: PROC[BoxProc]] ~ { data: Data ~ NARROW[device.data]; grayMaskBoxesAction: PROC ~ { GrayMaskBoxesInternal[data, bounds, boxes] }; ModifyColorFrame[vt: data.terminal, action: grayMaskBoxesAction, xmin: bounds.fmin, ymin: bounds.smin, xmax: bounds.fmax, ymax: bounds.smax]; }; GrayMaskBits: PROC[device: Device, srcBase: LONG POINTER, srcWordsPerLine: NAT, ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ { data: Data ~ NARROW[device.data]; grayMaskBitsBox: PROC[box: DeviceBox] ~ { grayMaskBitsBoxAction: PROC ~ { runs: PROC[run: RunProc] ~ { ImagerMask.RunsFromBits[ base: srcBase, wordsPerLine: srcWordsPerLine, sBits: box.smin-ts, fBits: box.fmin-tf, sRuns: box.smin, fRuns: box.fmin, sSize: box.smax-box.smin, fSize: box.fmax-box.fmin, run: run]; }; GrayMaskRunsInternal[data: data, bounds: box, runs: runs]; }; ModifyColorFrame[vt: data.terminal, action: grayMaskBitsBoxAction, xmin: box.fmin, ymin: box.smin, xmax: box.fmax, ymax: box.smax]; }; boxes[grayMaskBitsBox]; }; GrayMoveBoxes: PROC [device: Device, ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ TRUSTED { data: Data ~ NARROW[device.data]; frame: Terminal.FrameBuffer ~ data.frame; base: LONG POINTER ~ frame.base; wordsPerLine: NAT ~ frame.wordsPerLine; bbspace: PrincOps.BBTableSpace; bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace]; action: SAFE PROC ~ TRUSTED { PrincOpsUtils.BITBLT[bb] }; moveBox: PROC[box: DeviceBox] ~ TRUSTED { dfmin: NAT ~ Check[box.fmin, frame.width]; dsmin: NAT ~ Check[box.smin, frame.height]; dfmax: NAT ~ Check[box.fmax, frame.width]; dsmax: NAT ~ Check[box.smax, frame.height]; sfmin: NAT ~ dfmin-tf; ssmin: NAT ~ dsmin-ts; sfmax: NAT ~ dfmax-tf; ssmax: NAT ~ dsmax-ts; dstBit: CARDINAL ~ dfmin*bitsPerPixel; srcBit: CARDINAL ~ sfmin*bitsPerPixel; bpl: INTEGER _ wordsPerLine*bitsPerWord; ss: NAT _ ssmin; ds: NAT _ dsmin; bb.flags _ [disjoint: TRUE, disjointItems: TRUE, direction: forward, gray: FALSE]; IF dsminssmin THEN { bb.flags.disjoint _ FALSE; IF dsmin=ssmin AND dfminsfmin THEN bb.flags.disjointItems _ FALSE; IF dsmin>ssmin OR (dsmin=ssmin AND dfmin>sfmin) THEN { bb.flags.direction _ backward; bpl _ -bpl; ss _ ssmax-1; ds _ dsmax-1; }; }; bb.dst.word _ base+Basics.LongMult[ds, wordsPerLine]+dstBit/bitsPerWord; bb.dst.bit _ dstBit MOD bitsPerWord; bb.dstBpl _ bpl; bb.src.word _ base+Basics.LongMult[ss, wordsPerLine]+srcBit/bitsPerWord; bb.src.bit _ srcBit MOD bitsPerWord; bb.srcDesc.srcBpl _ bpl; bb.width _ (dfmax-dfmin)*bitsPerPixel; bb.height _ dsmax-dsmin; ModifyColorFrame[vt: data.terminal, action: action, xmin: MIN[dfmin, sfmin], ymin: MIN[dsmin, ssmin], xmax: MAX[dfmax, sfmax], ymax: MAX[dsmax, ssmax]]; }; bb^ _ nullBitBltTable; boxes[moveBox]; }; <<>> END.