The ScrnPaintOp interface

INTERFACE ScrnPaintOp;

IMPORT TrestleComm, PaintOp;

A ScrnPaintOp.T is a painting operation that is valid for some particular screentype.

If op is a ScrnPaintOp.T valid for screentype st, then op maps a source pixel s and destination pixel d to a result pixel op(d, s). It will be used in a painting operation that sets d := op(d, s). Both d and op(d, s) have type st, and s either has type st or st.bits. (The type st.bits is the screentype for one-bit deep sources that can be used with st.) For example, in a copy operation, s has type st, while in painting a bitmap, s has type st.bits.

A ScrnPaintOp.Oracle is meaningful only as the op field of some screentype st. It provides methods to generate ScreenPaintOp.Ts that are valid for st.

A tint is a paintop that is independent of s. If op is a tint, we write op(d) instead of op(d, s). (Even in the case of a tint, the type of s must be st.bits; otherwise the result of applying the tint is undefined.)

Obtaining handles from the oracle

TYPE 
  Pixel = INTEGER;
  Oracle = Private OBJECT
    METHODS
      <* LL.sup <= VBT.mu *>
      opaque(pix: Pixel): T 
        RAISES {Failure, TrestleComm.Failure};
      bgfg(bg, fg: T): T 
        RAISES {Failure, TrestleComm.Failure};
      swap(p,q: Pixel): T 
        RAISES {Failure, TrestleComm.Failure};
      transparent(): T 
        RAISES {Failure, TrestleComm.Failure};
      copy(): T 
        RAISES {Failure, TrestleComm.Failure}; 
      builtIn(op: PaintOp.Predefined): T;
    END;
    Private <: ROOT;
  
EXCEPTION Failure; 

For a screentype st, the field st.op is an Oracle whose methods satisfy the following specifications:

The method call

 op := st.op.opaque(pix)

sets op to a tint such that op(p) = pix for any p. The method call

 op := st.op.bgfg(bg, fg)

sets op to a tint such that op(p, 0) = bg(p) and op(p, 1) = fg(p), for any p, if bg and fg are tints. The method call

 op := st.op.swap(p, q)

sets op to a tint such that op(p)=q, op(q)=p, and for any x, op(op(x))=x. The method call

 op := st.op.transparent()

sets op to a tint such that op(p) = p for any p. The method call

 op := st.op.copy()

sets op to a painting operation such that op(p, q) = q for any p and q. The method call

 st.op.builtIn(op)

returns the operation valid for st that corresponds to the predefined screen-independent operation PaintOp.T{op}.

The exception Failure is raised if the screentype cannot provide the requested painting operation. For all the methods, LL.sup <= VBT.mu.

TYPE
  PlaneWiseOracle = Oracle OBJECT
    METHODS <* LL.sup <= VBT.mu *>
      planewise(
          READONLY mask: ARRAY OF BOOLEAN;
          op1, op2: T): T
        RAISES {Failure, TrestleComm.Failure};
  END;

If a screentype's op oracle is a PlaneWiseOracle (which you can test with TYPECASE), then you can use its planewise method to define painting operations by their effects on each bit position of the destination pixel. Let p[i] denote bit i of pixel p. Assuming NUMBER(mask) = st.depth, the method call

 op := st.op.planewise(mask, bitOps)

sets op so that for d and s of screentype st and i in [0..st.depth-1],

 IF mask[i] THEN
    op(d, s)[i] = op1(d[i], s[i])
 ELSE
    op(d, s)[i] = op2(d[i], s[i])
 END

The method may raise Failure if it does not support a particular combination of op1, op2, and mask.

The convenience procedure ConstructPlanewiseOp can be used to construct a painting operation from an array of boolean functions represented by the enumeration by BitOp:

TYPE
  BitOp = {
    Zero,           (* 0 *)
    And,            (* dest AND src *)
    NotAnd,         (* (NOT dest) AND src *)
    Src,            (* src *)
    AndNot,         (* dest and (NOT src) *)
    Dest,           (* dest *)
    Xor,            (* dest XOR src *)
    Or,             (* dest OR src *)
    Nor,            (* (NOT dest) AND (NOT src) *)
    Equal,          (* dest XOR (NOT src) *)
    Invert,         (* NOT dest *)
    NotOr,          (* (NOT dest) OR src *)
    NotSrc,         (* NOT src *)
    OrNot,          (* dest OR (NOT src) *)
    Nand,           (* (NOT dest) OR (NOT src) *)
    One};           (* 1 *)

PROCEDURE ConstructPlanewiseOp(
  pwo: PlaneWiseOracle;
  READONLY bitOps: ARRAY OF BitOp): T 
RAISES {Failure, TrestleComm.Failure}; 
<* LL.sup <= VBT.mu *>

Return the painting operation that applies bitOp[i] to plane i of the source and destination.

If NUMBER(bitOps) = st.depth then ConstructPlanewiseOp uses pwo to construct and return an operation op such that for s and d of screentype st and i in [0 .. st.depth-1],

  op(d, s)[i] = bitOps[i](d[i], s[i])

The procedure may raise Failure if the screentype does not support a particular array bitOps.

The handle object

TYPE 
  T <: Public; 
  Public = OBJECT id: INTEGER; pix: Pixel := -1 END;

If p is a T, then p.id is an identifier whose interpretation depends on the screentype. If p was created by a call st.op.opaque(pix), then p.pix = pix; otherwise p.pix = -1.

END ScrnPaintOp.