NStripe:
CEDAR
PROGRAM
IMPORTS Basics, PartitionDefs, Real
EXPORTS NStripeDefs =
BEGIN OPEN NStripeDefs;
Rect: TYPE = RECORD [x1, y1, x2, y2: INT];
OutOfBoundsNumber: PUBLIC ERROR = CODE;
half: REAL ← 0.5;
stripeHeight: CARDINAL = 256;
MaxX, MaxY: INT;
Round: PROCEDURE [x: REAL] RETURNS [INT] = INLINE
BEGIN RETURN[Real.Fix[x + half]]; END;
InitStripe:
PUBLIC
PROCEDURE [x:
CARDINAL, y:
CARDINAL] =
Set drawing limits in Mebes units
BEGIN MaxX ← x; MaxY ← y; END;
WriteRectangle:
PUBLIC
PROCEDURE [
Layer: PartitionDefs.layerNumber, Width, Height, X1, Y1: REAL] =
BEGIN
clipped: BOOL;
r: Rect;
stripe, stripeMax: PartitionDefs.stripeNumber;
stripeY: INT;
[clipped, r] ← RoundRect[X1, Y1, X1+Width, Y1+Height];
stripe ← Basics.LowHalf[r.y1/stripeHeight]; --number of lowest stripe
stripeMax ← Basics.LowHalf[r.y2/stripeHeight]; --number of highest stripe
stripeY ← INT[stripe]*INT[stripeHeight];
WHILE stripe <= stripeMax
DO
WriteStripedRectangle[stripe, Layer,
[x1: r.x1, y1: MAX[r.y1-stripeY, 0], x2: r.x2, y2: MIN[stripeHeight, r.y2-stripeY]]];
stripe ← stripe+1;
stripeY ← stripeY+stripeHeight;
ENDLOOP;
IF clipped THEN ERROR OutOfBoundsNumber;
END;
RoundRect:
PROC [x1, y1, x2, y2:
REAL]
RETURNS [clipped:
BOOL, r: Rect] =
BEGIN
clipped ← FALSE;
IF ((r.x1 ← Round[x1]) < 0) THEN {r.x1 ← 0; clipped ← TRUE};
IF ((r.y1 ← Round[y1]) < 0) THEN {r.y1 ← 0; clipped ← TRUE};
IF ((r.x2 ← Round[x2]) > MaxX) THEN {r.x2 ← MaxX; clipped ← TRUE};
IF ((r.y2 ← Round[y2]) > MaxY) THEN {r.y2 ← MaxY; clipped ← TRUE};
END;
rectangle: REF Rectangle ← NEW[Rectangle];
WriteStripedRectangle:
PROCEDURE [
Stripe: PartitionDefs.stripeNumber, Layer: PartitionDefs.layerNumber, r: Rect ] =
BEGIN
IF r.y1 < r.y2
AND r.x1 < r.x2
THEN
BEGIN
rectangle^ ← [
code: rectangleCode,
H: r.y2-r.y1,
W: r.x2-r.x1,
X1: r.x1,
Y1: r.y1];
TRUSTED {PartitionDefs.SendObjectToPartition[Stripe, Layer, [LOOPHOLE[rectangle], 0, Basics.bytesPerWord*SIZE[Rectangle]]]};
END;
END;
WriteTrapezoid:
PUBLIC
PROCEDURE [
Layer: PartitionDefs.layerNumber, Width, Height, X1, Y1, dX1, dX2: REAL] =
BEGIN
YMax: REAL ← Y1 + Height;
iY1: INT = Round[Y1];
iYMax: INT = Round[YMax];
StripeMin: PartitionDefs.stripeNumber ← Basics.LowHalf[iY1/stripeHeight]; --number of lowest stripe
StripeMax: PartitionDefs.stripeNumber ← Basics.LowHalf[iYMax/stripeHeight]; --number of highest stripe
StripeMinY: REAL = Real.Float[StripeMin]*Real.Float[stripeHeight];
IF Y1 < 0 OR iYMax > MaxY THEN ERROR OutOfBoundsNumber; --Xcheck in WriteStripedTrapezoid
IF StripeMin = StripeMax
--check for simple common case
THEN
WriteStripedTrapezoid[
StripeMin, Layer, Width, Height, X1, Y1 - StripeMinY, dX1, dX2]
ELSE
BEGIN
X2: REAL ← X1 + Width; --the right end of the base
x1, y1, x2: REAL; --updated values of X1,Y1,X2
h: REAL; --the traversed height
Stripe: PartitionDefs.stripeNumber;
first fragment
y1 ← StripeMinY + stripeHeight;
h ← y1 - Y1;
WriteStripedTrapezoid[
StripeMin, Layer, Width, h, X1, Y1 - StripeMinY, dX1, dX2];
middle fragments
x1 ← X1 + dX1*h;
x2 ← X2 + dX2*h;
FOR Stripe
IN (StripeMin..StripeMax)
DO
WriteStripedTrapezoid[
Stripe, Layer, x2 - x1, stripeHeight, x1, 0, dX1, dX2];
y1 ← y1 + stripeHeight;
h ← y1 - Y1;
x1 ← X1 + dX1*h;
x2 ← X2 + dX2*h;
ENDLOOP;
last fragment
WriteStripedTrapezoid[
StripeMax, Layer, x2 - x1, YMax - y1, x1, 0, dX1, dX2];
END;
END;
WriteStripedTrapezoid: PROCEDURE [
Stripe: PartitionDefs.stripeNumber, Layer: PartitionDefs.layerNumber,
mWidth, Height, mX1, Y1, mdX1, mdX2: REAL] =
BEGIN
Width: REAL = mWidth*16; --Convert abscissa info to 1/16 address units
dX1: REAL = mdX1*16; --ditto
dX2: REAL = mdX2*16; --ditto
X1: REAL = mX1*16; --ditto
X2: REAL = X1 + Width; --X coord of right end of base
Y2: REAL = Y1 + Height; --Y coord of top
iX1, iY2, iWidth, idX1, idX2: INT;
ciHeight, ciY1: CARDINAL;
ciY1 ← Round[Y1];
iX1 ← Round[X1];
iWidth ← Round[X2] - iX1;
iY2 ← Round[Y2];
ciHeight ← iY2 - ciY1;
idX1 ← Round[X1 + dX1*Height] - iX1;
idX2 ← Round[X2 + dX2*Height] - (iX1 + iWidth);
IF idX1 = 0
AND idX2 = 0
THEN
BEGIN -- it's a rectangle
clipped: BOOL;
r: Rect;
[clipped, r] ← RoundRect[mX1, Y1, mX1+mWidth, Y1+Height];
WriteStripedRectangle[Stripe, Layer, r];
IF clipped THEN ERROR OutOfBoundsNumber;
END
ELSE
BEGIN -- it's a non-rectangle form of trapezoid
IF iX1 < 0
OR iX1 + idX1 < 0
OR iX1 + iWidth > MaxX*16
OR iX1 + iWidth + idX2 > MaxX*16 THEN ERROR OutOfBoundsNumber;
IF (iWidth = 0 AND idX1 = idX2) OR ciHeight = 0 THEN RETURN;
SELECT
TRUE
FROM
idX1 = idX2 =>
WriteStripedParallelogram[
Stripe, Layer, iWidth, ciHeight, iX1, ciY1, idX1];
idX2 = 0 =>
WriteStripedTrapezoid1[Stripe, Layer, iWidth, ciHeight, iX1, ciY1, idX1];
idX1 = 0 =>
WriteStripedTrapezoid2[Stripe, Layer, iWidth, ciHeight, iX1, ciY1, idX2];
ENDCASE =>
WriteStripedTrapezoid3[
Stripe, Layer, iWidth, ciHeight, iX1, ciY1, idX1, idX2];
END;
END;
Low:
PROC [ i:
INT ]
RETURNS [ n:
CARDINAL ] =
{RETURN[Basics.LowHalf[LOOPHOLE[i]]]};
High:
PROC [ i:
INT ]
RETURNS [ n: [0..100B) ] =
BEGIN
hi: INTEGER;
TRUSTED {hi ← LOOPHOLE[Basics.HighHalf[i]]};
IF ~ (hi IN [-40B..40B) ) THEN ERROR;
RETURN[IF hi>=0 THEN hi ELSE hi+100B];
END;
quad: REF BasicQuadrilateral ← NEW[BasicQuadrilateral];
WriteStripedParallelogram:
PROCEDURE [
Stripe: PartitionDefs.stripeNumber, Layer: PartitionDefs.layerNumber, Width: LONG CARDINAL,
Height: CARDINAL, X1: LONG CARDINAL, Y1: CARDINAL, dX: INT] =
TRUSTED BEGIN
quad^ ← [
code: parallelogramCode,
H: Height,
W: Low[Width],
X1: Low[X1],
Y1: Y1,
DX: Low[dX],
DXHigh: High[dX],
X1High: High[X1],
WHigh: High[Width]];
PartitionDefs.SendObjectToPartition[Stripe, Layer, [LOOPHOLE[quad], 0, Basics.bytesPerWord*SIZE[BasicQuadrilateral]]];
END;
WriteStripedTrapezoid1:
PROCEDURE [
Stripe: PartitionDefs.stripeNumber, Layer: PartitionDefs.layerNumber, Width: LONG CARDINAL,
Height: CARDINAL, X1: LONG CARDINAL, Y1: CARDINAL, dX: INT] =
TRUSTED BEGIN
quad^ ← [
code: trapezoid1Code,
H: Height,
W: Low[Width],
X1: Low[X1],
Y1: Y1,
DX: Low[dX],
DXHigh: High[dX],
X1High: High[X1],
WHigh: High[Width]];
PartitionDefs.SendObjectToPartition[Stripe, Layer, [LOOPHOLE[quad], 0, Basics.bytesPerWord*SIZE[BasicQuadrilateral]]];
END;
WriteStripedTrapezoid2:
PROCEDURE [
Stripe: PartitionDefs.stripeNumber, Layer: PartitionDefs.layerNumber, Width: LONG CARDINAL,
Height: CARDINAL, X1: LONG CARDINAL, Y1: CARDINAL, dX: INT] =
TRUSTED BEGIN
quad^ ← [
code: trapezoid2Code,
H: Height,
W: Low[Width],
X1: Low[X1],
Y1: Y1,
DX: Low[dX],
DXHigh: High[dX],
X1High: High[X1],
WHigh: High[Width]];
PartitionDefs.SendObjectToPartition[Stripe, Layer, [LOOPHOLE[quad], 0, Basics.bytesPerWord*SIZE[BasicQuadrilateral]]];
END;
trapezoid3: REF Trapezoid3 ← NEW[Trapezoid3];
WriteStripedTrapezoid3:
PROCEDURE [
Stripe: PartitionDefs.stripeNumber, Layer: PartitionDefs.layerNumber, Width: LONG CARDINAL,
Height: CARDINAL, X1: LONG CARDINAL, Y1: CARDINAL, dX1: INT,
dX2: INT] =
TRUSTED BEGIN
trapezoid3^ ← [
code: trapezoid3Code,
H: Height,
W: Low[Width],
X1: Low[X1],
DX2High: High[dX2],
Y1: Y1,
DX1: Low[dX1],
DX2: Low[dX2],
DX1High: High[dX1],
X1High: High[X1],
WHigh: High[Width]];
PartitionDefs.SendObjectToPartition[Stripe, Layer, [LOOPHOLE[trapezoid3], 0, Basics.bytesPerWord*SIZE[Trapezoid3]]];
END;
END.