-- CGPressDeviceImpl.mesa -- Last changed by Doug Wyatt, April 21, 1982 3:59 pm -- Last changed by Warnock June 4, 1982 1:38 pm -- Last changed by Plass and Stone October 1, 1982 10:19 am DIRECTORY GraphicsBasic, CGArea USING [Empty, Ref, Remove], CGPressDevice, CGDevice USING [Ref, Rep], CGMatrix USING [Inv, InvRel, Make, Ref], CGSource USING [Mode, Ref, Type], CGStorage USING [qZone], SirPress, Inline, GraphicsColor USING [Color, ColorToHSV], Real USING [Fix, FixC, RoundLI]; CGPressDeviceImpl: MONITOR IMPORTS CGArea, CGMatrix, CGStorage, Inline, Real,SirPress, GraphicsColor EXPORTS GraphicsBasic, CGPressDevice = { DeviceObject:PUBLIC TYPE = CGDevice.Rep; dataZone: ZONE = CGStorage.qZone; repZone: ZONE = CGStorage.qZone; Error: SIGNAL = CODE; Data: TYPE = REF DataRep; DataRep: TYPE = RECORD [ ph:SirPress.PressHandle, unit: INT, fatness: REAL, halftoneSubsamplingFactor: REAL, matrix: CGMatrix.Ref -- base transformation matrix ]; New: PUBLIC PROC [ pressHandle: SirPress.PressHandle, resolution: REAL, -- in bits per inch halftoneResolution: REAL, -- maximum resolution for halftone images, in pixels per inch fatness: REAL -- in points (72 points per inch) ] RETURNS [CGDevice.Ref] = { s: REAL _ resolution/72.0; data: Data _ dataZone.NEW[DataRep _ [ ph: pressHandle, unit: Real.RoundLI[SirPress.pt/s], fatness: fatness, halftoneSubsamplingFactor: resolution/halftoneResolution, matrix: CGMatrix.Make[[s,0,0,s,0,0]]]]; SirPress.SetColor[pressHandle,0,0,0]; RETURN[repZone.NEW[CGDevice.Rep _ [ GetMatrix: GetMatrix, GetBounds: GetBounds, Show: Show, GetRaster: GetRaster, data: data]]]; }; GetMatrix: SAFE PROC[self: CGDevice.Ref] RETURNS [CGMatrix.Ref] = CHECKED { data: Data _ NARROW[self.data]; RETURN[data.matrix]; }; GetBounds: SAFE PROC[self: CGDevice.Ref] RETURNS [GraphicsBasic.Box] = CHECKED { data: Data _ NARROW[self.data]; e: REAL = 0.1; -- small fudge factor RETURN[[xmin: e, ymin: e, xmax: 17*SirPress.in/(2*data.unit)-e, ymax: 11*SirPress.in/data.unit-e]]; }; GetRaster: SAFE PROC[self: CGDevice.Ref] RETURNS [LONG POINTER,CARDINAL] = CHECKED { RETURN[NIL,0]; }; Show: SAFE PROC[self: CGDevice.Ref, area: CGArea.Ref, src: CGSource.Ref, map: CGMatrix.Ref] = TRUSTED { data: Data _ NARROW[self.data]; SetColor[data.ph,src.color]; UNTIL CGArea.Empty[area] DO trap: GraphicsBasic.Trap _ CGArea.Remove[area]; ShowTrap[data,trap,src,map]; ENDLOOP; }; SetColor: PROC[pressHandle: SirPress.PressHandle, color: GraphicsColor.Color] = { h,s,v: REAL; [h,s,v] _ GraphicsColor.ColorToHSV[color]; SirPress.SetColor[pressHandle,Real.RoundLI[h*240],Real.RoundLI[s*255],Real.RoundLI[v*255]]; }; Store: PROC [scanLine: REF SirPress.ScanLine, index: NAT, sample: CARDINAL] = { WITH scanLine: scanLine SELECT FROM bitMap => scanLine[index] _ sample; bitSampled => scanLine[index] _ sample; bitBitSampled => scanLine[index] _ sample; nybbleSampled => scanLine[index] _ sample; byteSampled => scanLine[index] _ sample; ENDCASE => ERROR; }; Bot: PROC[r: REAL] RETURNS [CARDINAL] = INLINE { RETURN[Real.FixC[r]] }; Top: PROC[r: REAL] RETURNS [CARDINAL] = INLINE { RETURN[Real.FixC[r]+1] }; Fix: PROC[r: REAL] RETURNS [CARDINAL] = INLINE { RETURN[Real.FixC[r]] }; Rnd: PROC[r: REAL] RETURNS [CARDINAL] = INLINE { RETURN[Real.FixC[r+.5]] }; RndI: PROC[r: REAL] RETURNS [INTEGER] = INLINE { RETURN[Real.FixC[r+(LAST [INTEGER]+.5)]-LAST[INTEGER]] }; RndUp: PROC[c, m: CARDINAL] RETURNS [CARDINAL] = INLINE {RETURN[(c+(m-1))/m*m]}; White: PROC[bitsPerSample: [0..16]] RETURNS [intensity: CARDINAL] = { intensity _ Inline.BITSHIFT[1, bitsPerSample]; intensity _ intensity-1; }; Line1: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..1B]]; Line2: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..3B]]; Line4: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..17B]]; Line8: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..377B]]; AGet: PROC[src: CGSource.Ref, x,y: CARDINAL] RETURNS[CARDINAL] = INLINE { xline: LONG POINTER _ src.xbase + Inline.LongMult[y,src.xrast]; SELECT src.bps FROM 0,1 => RETURN[LOOPHOLE[xline, LONG POINTER TO Line1][x]]; 2 => RETURN[LOOPHOLE[xline, LONG POINTER TO Line2][x]]; 4 => RETURN[LOOPHOLE[xline, LONG POINTER TO Line4][x]]; 8 => RETURN[LOOPHOLE[xline, LONG POINTER TO Line8][x]]; ENDCASE => ERROR; }; Frac: TYPE = Inline.LongNumber; fscl: Frac = [num[lowbits: 0, highbits: 1]]; FixF: PROC[r: REAL] RETURNS[Frac] = INLINE { RETURN[[li[Real.Fix[r*fscl.li]]]] }; FltF: PROC[f: Frac] RETURNS[REAL] = INLINE { r: REAL _ f.li; RETURN[r/fscl.li] }; AddF: PROC[a,b: Frac] RETURNS[Frac] = INLINE { RETURN[[li[a.li+b.li]]] }; IntF: PROC[f: Frac] RETURNS[INTEGER] = INLINE { RETURN[LOOPHOLE[f.highbits, INTEGER]] }; ShowTrap: ENTRY PROC[data: Data, trap: GraphicsBasic.Trap, src: CGSource.Ref, map: CGMatrix.Ref] = { type: CGSource.Type _ src.type; easy: BOOLEAN _ (SELECT type FROM const => TRUE, -- always easy array, tile => FALSE, -- Not easy proc => FALSE, -- never easy ENDCASE => ERROR); fat: BOOLEAN _ src.fat; yb, yt, yl, xl, xr: CARDINAL _ 0; rdxl, rdxr: REAL _ 0; -- left and right x increments rsdx, rsdy: REAL _ 0; -- increments for source position fsdx, fsdy: Frac; mode: CGSource.Mode _ src.mode; white: CARDINAL _ White[src.bps]; PutTrap: PROC[xbotL, xtopL, xtopR, xbotR, ybot, ytop: INT] = { IF xbotL=xtopL AND xbotR=xtopR THEN SirPress.PutRectangle[data.ph, xbotL, ybot, xbotR-xbotL, ytop-ybot, data.unit] ELSE { SirPress.StartOutline[data.ph]; SirPress.PutMoveTo[data.ph, xbotL, ybot, data.unit]; SirPress.PutDrawTo[data.ph, xtopL, ytop, data.unit]; SirPress.PutDrawTo[data.ph, xtopR, ytop, data.unit]; SirPress.PutDrawTo[data.ph, xbotR, ybot, data.unit]; SirPress.EndOutline[data.ph]; } }; -- main code for PTrap starts here -- compute yb (bottom of first scanline) and yt (top of last scanline) IF fat THEN { yb_Bot[trap.ybot]; yt_Top[trap.ytop] } ELSE { yb_Rnd[trap.ybot]; yt_Rnd[trap.ytop] }; IF ybyt OR fat THEN SIGNAL Error; RETURN }; IF easy THEN { --constant color trapezoid IF fat THEN PutTrap[ xbotL: Bot[trap.xbotL], xtopL: Bot[trap.xtopL], xtopR: Top[trap.xtopR], xbotR: Top[trap.xbotR], ybot: yb, ytop: yt ] ELSE PutTrap[ xbotL: Rnd[trap.xbotL], xtopL: Rnd[trap.xtopL], xtopR: Rnd[trap.xtopR], xbotR: Rnd[trap.xbotR], ybot: yb, ytop: yt ] } ELSE { --going to put out a showbits command with carefully placed 0's scanLine: REF SirPress.ScanLine; -- allocate storage for a scan line. scanLineOrigin: CARDINAL _ Bot[MIN[trap.xbotL, trap.xtopL]]; scanLineEnd: CARDINAL _ Top[MAX[trap.xbotR, trap.xtopR]]; scanLineLength: CARDINAL _ SELECT src.bps FROM 0 => RndUp[scanLineEnd - scanLineOrigin, 16], 1 => RndUp[scanLineEnd - scanLineOrigin, 16], 2 => RndUp[scanLineEnd - scanLineOrigin, 8], 4 => RndUp[scanLineEnd - scanLineOrigin, 4], 8 => RndUp[scanLineEnd - scanLineOrigin, 2], ENDCASE => ERROR; DoLine: PROC[xmin, xmax, y: CARDINAL] = { rsx, rsy: REAL; -- current source position fsx, fsy: Frac; sx, sy: CARDINAL; -- truncated source position s: CARDINAL; -- sample value from source FOR x: CARDINAL IN [scanLineOrigin..xmin) DO Store[scanLine, x-scanLineOrigin, white] ENDLOOP; FOR x: CARDINAL IN [xmin..xmax) DO --put in the rest of the samples IF x=xmin THEN { [[rsx,rsy]] _ CGMatrix.Inv[map,[x+0.5,y+0.5]]; fsx _ FixF[rsx]; fsy _ FixF[rsy]; } ELSE { fsx _ AddF[fsx,fsdx]; fsy _ AddF[fsy,fsdy]}; -- Get a sample from the source IF type=proc THEN s _ src.Get[FltF[fsx], FltF[fsy]] ELSE { sx _ IntF[fsx]; sy _ IntF[fsy]; s _ AGet[src, sx, sy] }; Store[scanLine, x-scanLineOrigin, s] ENDLOOP; FOR x: CARDINAL IN [xmax..scanLineEnd) DO Store[scanLine, x-scanLineOrigin, white] ENDLOOP; SirPress.ShowLine[data.ph, scanLine]; }; SELECT src.bps FROM 0 => scanLine _ NEW[SirPress.ScanLine[bitMap][scanLineLength]]; 1 => scanLine _ NEW[SirPress.ScanLine[bitSampled][scanLineLength]]; 2 => scanLine _ NEW[SirPress.ScanLine[bitBitSampled][scanLineLength]]; 4 => scanLine _ NEW[SirPress.ScanLine[nybbleSampled][scanLineLength]]; 8 => scanLine _ NEW[SirPress.ScanLine[byteSampled][scanLineLength]]; ENDCASE => ERROR; FOR i: NAT IN [scanLineEnd-scanLineOrigin..scanLineLength) DO Store[scanLine, i, white] ENDLOOP; --if opaque, then blot out the trapezoidal region IF src.mode=opaque THEN { SirPress.SetColor[data.ph, 0, 0, 255]; PutTrap[ xbotL: Rnd[trap.xbotL], xtopL: Rnd[trap.xtopL], xtopR: Rnd[trap.xtopR], xbotR: Rnd[trap.xbotR], ybot: yb, ytop: yt ]; SetColor[data.ph, src.color]; }; SirPress.BeginScannedRectangle[ p: data.ph, x: scanLineOrigin, y: yb, dotsPerLine: scanLineLength, numberOfLines: yt-yb, width: scanLineLength, height: yt-yb, unit: data.unit, nextLineDirection: up, nextDotDirection: right, coding: (WITH scanLine SELECT FROM bitMap => bitMap, packedMap => packedMap, bitSampled => bitSampled, bitBitSampled => bitBitSampled, nybbleSampled => nybbleSampled, byteSampled => byteSampled, ENDCASE => ERROR)]; --set up for getting samples out of a sampled source [[rsdx, rsdy]] _ CGMatrix.InvRel[map,[1,0]]; rsdx _ rsdx; rsdy _ rsdy; fsdx _ FixF[rsdx]; fsdy _ FixF[rsdy]; --set up for the scan converter rdxl_(trap.xtopL-trap.xbotL); -- delta x, left rdxr_(trap.xtopR-trap.xbotR); -- delta x, right IF NOT(fat AND yb=yl) THEN { rdy: REAL_trap.ytop-trap.ybot; -- delta y rdxl_rdxl/rdy; rdxr_rdxr/rdy; -- dx/dy, left right }; IF fat THEN { rxlb,rxrb,rxlt,rxrt: REAL _ 0; -- x at bottom and top of current line ltop: BOOLEAN _ rdxl<0; -- TRUE means leftmost x is at top of line rtop: BOOLEAN _ rdxr>0; -- TRUE means rightmost x is at top of line FOR y: CARDINAL IN[yb..yl] DO -- for each scan line IF y=yb THEN { rxlb_trap.xbotL; rxrb_trap.xbotR } -- first line ELSE { rxlb_rxlt; rxrb_rxrt }; -- successive lines IF y=yl THEN { rxlt_trap.xtopL; rxrt_trap.xtopR } -- last line ELSE IF y=yb THEN { -- first line, if yl>yb d: REAL_(yb+1)-trap.ybot; -- distance to top of line rxlt_rxlb+d*rdxl; rxrt_rxrb+d*rdxr } ELSE { rxlt_rxlb+rdxl; rxrt_rxrb+rdxr }; -- middle lines xl_Bot[IF ltop THEN rxlt ELSE rxlb]; xr_Top[IF rtop THEN rxrt ELSE rxrb]; IF xl