G3dEdgeBltImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Frank Crow, July 2, 1987 4:01:00 pm PDT
A general-purpose Bresenham incrementer.
DIRECTORY
Basics, G3dEdgeBlt, Rope;
G3dEdgeBltImpl: CEDAR PROGRAM
IMPORTS Basics
EXPORTS G3dEdgeBlt
~ BEGIN
Type Definitions
LongNumber:    TYPE ~ Basics.LongNumber;
BytePair:      TYPE ~ Basics.BytePair;
ROPE:      TYPE ~ Rope.ROPE;
EdgeDesc:     TYPE ~ G3dEdgeBlt.EdgeDesc;
RECORD[
val: INT32,     -- current value for incrementation, byte address or value
stepsLeft: WORD ← 0,  -- number of increments remaining
length: WORD ← 0,   -- total number of increments to make 
hiccups: WORD ← 0,   -- number of offsets (hiccups) to make
lngthIncr: INTEGER ← 0, -- amount to increment by
hicIncr: INTEGER ← 0,  -- amount to offset at hiccup
bias: INTEGER ← 0,   -- change to number of increments to first offset (for wizards)
indirect: BOOLEANTRUE, -- incrementing addresses if TRUE, else values
nextEdge: CARD16 ← 0 -- next edge if part of a chain of edges (index in Sequence)
];
EdgeSequence:    TYPE ~ G3dEdgeBlt.EdgeSequence;
RECORD [length: NAT ← 0, s: SEQUENCE maxLength: NAT OF EdgeDesc];
EdgeBltTable:    TYPE ~ G3dEdgeBlt.EdgeBltTable;
EdgeBltOptions:    TYPE ~ G3dEdgeBlt.EdgeBltOptions;
Error:      PUBLIC SIGNAL [code: ATOM, reason: ROPE] = CODE;
Constants
longZero: LongNumber ~ [lc[0]];
longOne: LongNumber ~ [lc[1]];
Basic Procedures
The fractional increment Dx/Dy must be added to y for every new position x. Whenever the fraction overflows, y is incremented, effectively subtracting 1 from the fraction. By removing the fractional part from y, we can instead increment by Dy until Dx is reached. To center the positions of the y-increments along x, the incrementation by Dy should be started at Dx/2. To further simplify, decrement by 2Dy and start at Dx, testing for < 0. In the following read Dx as longSize and Dy as shortSize.
Incr: PUBLIC PROC[edge: EdgeDesc, array: REF EdgeSequence ← NIL] RETURNS[EdgeDesc] ~ {
edge.val ← edge.val + edge.lngthIncr;
edge.bias ← edge.bias - 2*edge.hiccups;
IF edge.bias <= 0 THEN {
edge.val ← edge.val + edge.hicIncr;
edge.bias ← edge.bias + 2*edge.length;
};
edge.stepsLeft ← edge.stepsLeft - 1;
IF edge.stepsLeft <= 0        -- Get next linked edge if this one exhausted
THEN IF edge.nextEdge # 0 THEN edge ← array[edge.nextEdge];
RETURN[edge];
};
InlineIncr: PROC[edge: EdgeDesc, array: REF EdgeSequence ← NIL]
    RETURNS[EdgeDesc] ~ INLINE {
edge.val ← edge.val + edge.lngthIncr;
edge.bias ← edge.bias - 2*edge.hiccups;
IF edge.bias <= 0 THEN {
edge.val ← edge.val + edge.hicIncr;
edge.bias ← edge.bias + 2*edge.length;
};
edge.stepsLeft ← edge.stepsLeft - 1;
IF edge.stepsLeft <= 0        -- Get next linked edge if this one exhausted
THEN IF edge.nextEdge # 0 THEN edge ← array[edge.nextEdge];
RETURN[edge];
};
Blt: PUBLIC PROC[ebt: EdgeBltTable] ~ {
DoByte: PROC[] ~ INLINE {
dstAddr: LONG POINTERLOOPHOLE[Basics.DoubleShiftRight[LOOPHOLE[dst.val], 1]];
srcValue: BYTE;
IF src.indirect
THEN TRUSTED {             -- get lo byte of word
srcAddr: LONG POINTERLOOPHOLE[Basics.DoubleShiftRight[LOOPHOLE[src.val], 1]];
srcValue ← LOOPHOLE[srcAddr^, BytePair].low
}
ELSE srcValue ← LOOPHOLE[src.val, LongNumber.bytes].ll; -- lo byte, lo half of long
IF Basics.DoubleAnd[LOOPHOLE[dst.val], longOne] # longZero -- lo byte? (right pixel)
THEN TRUSTED { LOOPHOLE[dstAddr^, BytePair].lowsrcValue; } -- right pixel
ELSETRUSTED { LOOPHOLE[dstAddr^, BytePair].high ← srcValue; }; -- left pixel
};
dst: EdgeDesc ← ebt.dst;
src: EdgeDesc ← ebt.src;
options: EdgeBltOptions ← ebt.options;
IF NOT dst.indirect THEN Error[$Fatal, "Destination value must be address"];
dst.bias ← dst.bias + dst.length;  -- initial bias to center hiccups
src.bias ← src.bias + src.length;
dst.stepsLeft ← dst.length;    -- set stepsLeft for count down
src.stepsLeft ← src.length;
IF options.includeStart THEN DoByte[];
FOR i: CARDINAL IN (0 .. dst.length) DO
dst ← InlineIncr[dst]; IF src.length > 0 THEN src ← InlineIncr[src]; DoByte[];
ENDLOOP;
IF options.includeEnd THEN {
dst ← InlineIncr[dst]; IF src.length > 0 THEN src ← InlineIncr[src]; DoByte[];
};
};
END.