ImagerDisplayMasksImpl.mesa
Last Edited by: Crow, September 1, 1983 2:08 pm
DIRECTORY
Environment USING [LongNumber],
Inline USING [BITOR, BITAND, HighHalf],
Real USING [FixI],
ImagerBasic USING [Path, Pair, IntPair, Rectangle, IntRectangle, PixelArray,
Transformation, StrokeEnds],
ImagerTransform USING [Transform, IntTransform, TransformIntRectangle],
ImagerDisplay USING [ContextData],
ImagerMasks USING [Mask],
Imager USING [Context];
Client Procedures (exported to Imager)
MaskStroke: PUBLIC PROC [context: Imager.Context, path: ImagerBasic.Path, width: REAL,
strokeEnds: ImagerBasic.StrokeEnds, closed:
BOOLEAN ←
FALSE] = {
Form a stencil of "width" thickness around a spine defined by "path".
Connected path segments will be mitered together. If the first and last points of a trajectory coincide, the path will be closed and mitered.
displayContext: ImagerDisplay.ContextData = NARROW[context.data];
};
MaskFill:
PUBLIC PROC [context: Imager.Context, path: ImagerBasic.Path] = {
Use the path to outline an area to be filled with the source
displayContext: ImagerDisplay.ContextData = NARROW[context.data];
};
MaskPixel:
PUBLIC PROC [context: Imager.Context, pixelArray: ImagerBasic.PixelArray] = {
Use the supplied pixel array as the stencil. The origin of the pixel array will be placed at the origin of the client space. The samples will be assumed to be placed at one unit intervals in the client space.
displayContext: ImagerDisplay.ContextData = NARROW[context.data];
};
Fast Track. The width of lines, etc. is device dependent, approximately .1% page height.
MaskBits: PUBLIC PROC [context: Imager.Context, base: LONG POINTER, raster: CARDINAL,
tile: ImagerBasic.IntRectangle, area: ImagerBasic.IntRectangle] = {
};
Draw line using current color
MaskSegment:
PUBLIC
PROC [context: Imager.Context, p: ImagerBasic.Pair] = {
displayContext: ImagerDisplay.ContextData = NARROW[context.data];
p ← ImagerTransform.Transform[p, displayContext.transform];
DrawSegment[ [ Real.FixI[p.x], Real.FixI[p.y] ] , displayContext];
};
MaskIntSegment:
PUBLIC
PROC [context: Imager.Context, p: ImagerBasic.IntPair] = {
displayContext: ImagerDisplay.ContextData = NARROW[context.data];
p ← ImagerTransform.IntTransform[p, displayContext.transform];
DrawSegment[p, displayContext];
};
MaskThinStroke:
PUBLIC
PROC [context: Imager.Context, path: ImagerBasic.Path] = {};
Draw whole path using the current color
MaskRectangle:
PUBLIC
PROC [context: Imager.Context, area: ImagerBasic.Rectangle] = {};
Fill rectangular area with the current color
MaskIntRectangle:
PUBLIC
PROC [context: Imager.Context, area: ImagerBasic.IntRectangle] = {
left, bottom, right, top: INTEGER;
displayContext: ImagerDisplay.ContextData = NARROW[context.data];
area ← ImagerTransform.TransformIntRectangle[area, displayContext.transform];
left ← MAX[area.x, displayContext.clipper.fMin];
bottom ← MAX[area.y, displayContext.clipper.sMin];
right ← MIN[left + area.w,
displayContext.clipper.fMin + displayContext.clipper.fSize];
top ← MIN[bottom + area.h,
displayContext.clipper.sMin + displayContext.clipper.sSize];
displayContext.deviceProcs.LoadTrapezoid[
displayContext,
top, bottom, left, left, right, right,
displayContext.currentPxlValue];
};
Internal Procedures
DrawSegment:
PROC [p: ImagerBasic.IntPair, displayContext: ImagerDisplay.ContextData] =
INLINE {
IF displayContext.noClip
THEN {
OPEN displayContext;
deviceProcs.DrawLine[displayContext, currentPosition, p, currentPxlValue]; }
ELSE
IF displayContext.clipper.refRep =
NIL
-- rectangular?
THEN { in:
BOOLEAN; a, b: ImagerBasic.IntPair;
[in, a, b] ← ClipEdgeByRectangle[displayContext.clipper,
displayContext.currentPosition, p];
IF in THEN displayContext.deviceProcs.DrawLine[displayContext, a, b,
displayContext.currentPxlValue];
}
ELSE ERROR NotImplementedYet[]; -- until paths are worked out - M. Plass?
displayContext.currentPosition ← p;
};
ClipEdgeByRectangle: PROC [clipper: ImagerMasks.Mask, a, b: ImagerBasic.IntPair]
RETURNS [
BOOLEAN, ImagerBasic.IntPair, ImagerBasic.IntPair] =
INLINE {
Out: TYPE = RECORD[bottom, top, left, right: BOOLEAN];
noneOut: Out = [FALSE, FALSE, FALSE, FALSE];
Code:
PROC [x, y:
INTEGER]
RETURNS [Out] =
INLINE {
OPEN clipper;
out: Out ← noneOut;
IF x < fMin THEN out.left ← TRUE; IF x > fMin + fSize THEN out.right ← TRUE;
IF y < sMin THEN out.bottom ← TRUE; IF y > sMin + sSize THEN out.top ← TRUE;
RETURN [ out ];
};
ClipY:
PROC [a, b: ImagerBasic.IntPair, xPos:
INTEGER]
RETURNS [
INTEGER] =
INLINE {
t: Environment.LongNumber;
t.high ← LOOPHOLE[xPos - a.x, UNSPECIFIED]; t.low ← LOOPHOLE[0, UNSPECIFIED];
RETURN[ a.y +
LOOPHOLE[
Inline.HighHalf[ LOOPHOLE[t, LONG INTEGER] / (b.x - a.x) * (b.y - a.y)], INTEGER] ];
};
ClipX:
PROC [a, b: ImagerBasic.IntPair, yPos:
INTEGER]
RETURNS [
INTEGER] =
INLINE {
t: Environment.LongNumber;
t.high ← LOOPHOLE[yPos - a.y, UNSPECIFIED]; t.low ← LOOPHOLE[0, UNSPECIFIED];
RETURN[ a.x +
LOOPHOLE[
Inline.HighHalf[ LOOPHOLE[t, LONG INTEGER] / (b.y - a.y) * (b.x - a.x)], INTEGER] ];
};
aCode, bCode, out: Out;
c: ImagerBasic.IntPair;
WHILE
TRUE
DO
aCode ← Code[a.x, a.y]; bCode ← Code[b.x, b.y];
Trivial acceptance test
IF Inline.BITOR[LOOPHOLE[aCode, UNSPECIFIED], LOOPHOLE[bCode, UNSPECIFIED]]
= LOOPHOLE[0, UNSPECIFIED]
THEN
RETURN[
TRUE, a, b];
Trivial rejection test
IF Inline.BITAND[LOOPHOLE[aCode, UNSPECIFIED], LOOPHOLE[bCode, UNSPECIFIED]]
# LOOPHOLE[0, UNSPECIFIED]
THEN
RETURN[
FALSE, a, b];
Actual clipping necessary
out ← IF aCode # noneOut THEN aCode ELSE bCode;
SELECT TRUE FROM
out.left => { c.x ← clipper.fMin;
c.y ← ClipY[a, b, c.x]; };
out.right => { c.x ← clipper.fMin + clipper.fSize;
c.y ← ClipY[a, b, c.x]; };
out.bottom => { c.y ← clipper.sMin;
c.x ← ClipX[a, b, c.y]; };
out.top => { c.y ← clipper.sMin + clipper.sSize;
c.x ← ClipX[a, b, c.y]; }
ENDCASE;
IF aCode = out THEN a ← c ELSE b ← c;
ENDLOOP;
ERROR; -- can't get here, supposedly
};
END.