-- 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 yb<yt THEN yl←yt-1 -- yl is last line
ELSE { IF yb>yt 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<xr THEN DoLine[xmin: xl, xmax: xr, y: y];
ENDLOOP;
}
ELSE {
rxl,rxr: REAL ← 0; -- left and right x at middle of current line
FOR y: CARDINAL IN[yb..yl] DO -- for each scan line
IF y=yb THEN { -- first line
d: REAL←(yb+0.5)-trap.ybot; -- distance to middle of line
rxl←trap.xbotL+d*rdxl; rxr←trap.xbotR+d*rdxr }
ELSE { rxl←rxl+rdxl; rxr←rxr+rdxr }; -- successive lines
xl←Rnd[rxl]; xr←Rnd[rxr];
IF xl<xr THEN DoLine[xl,xr,y];
ENDLOOP;
};
SirPress.EndScannedRectangle[data.ph];
};
};
}.