-- CGBitmapImpl.mesa
-- Last changed by Doug Wyatt, October 4, 1982 11:37 am

DIRECTORY
CGArea USING [Ref],
CGBitmapDevice USING [New],
CGClipper USING [SetBox],
CGContext USING [GenBox, Ref, ResetPool],
CGDevice USING [Ref],
CGMatrix USING [Assign, Concat, Id, Map, New, Ref, SetTrans, Translate],
CGPrivate USING [Context],
CGScreen USING [Bits],
CGSource USING [Ref, Rep],
CGStorage USING [pZone, qZone],
GraphicsBasic USING [black, Box, Vec],
GraphicsOps USING [BitmapRef, BitmapRep, Texture];

CGBitmapImpl: CEDAR PROGRAM
IMPORTS CGBitmapDevice, CGClipper, CGContext, CGMatrix, CGScreen, CGStorage
EXPORTS CGContext, CGPrivate, GraphicsOps = { OPEN GraphicsBasic;

BitmapRef: TYPE = GraphicsOps.BitmapRef;
BitmapRep: TYPE = GraphicsOps.BitmapRep;

Data: TYPE = REF DataRep;
DataRep: PUBLIC TYPE = RECORD [
lastid: CGMatrix.Id, -- id of last matrix used to form map
map: CGMatrix.Ref, -- bitmap to device matrix
mask: CGSource.Ref -- source info for bitmap
];

Context: TYPE = CGPrivate.Context;
ContextData: TYPE = CGContext.Ref;
BitmapDataRep: PUBLIC TYPE = DataRep; -- export into CGContext

dataZone: ZONE = CGStorage.qZone;
srcZone: ZONE = CGStorage.qZone;
repZone: ZONE = CGStorage.qZone;
bitmapZone: ZONE = CGStorage.pZone;

GetData: PROC[self: ContextData] RETURNS[Data] = INLINE {
data: Data ← self.bitmapdata;
RETURN[IF data=NIL THEN MakeData[self] ELSE data] };

MakeData: PROC[self: ContextData] RETURNS[Data] = {
data: Data ← dataZone.NEW[DataRep ← [lastid: 0, map: NIL, mask: NIL]];
data.map ← CGMatrix.New[];
data.mask ← srcZone.NEW[CGSource.Rep ← [type: array, mode: opaque,
fat: FALSE, bps: 0, color: GraphicsBasic.black, xbase: NIL, xrast: 0, Get: NIL]];
self.bitmapdata ← data;
RETURN[data];
};

DrawBits: PUBLIC UNSAFE PROC[self: Context, base: LONG POINTER, raster: CARDINAL,
bitsPerPixel: [0..16), x, y, w, h: CARDINAL, xorigin, yorigin: INTEGER] = CHECKED {
ctx: ContextData ← NARROW[self.data];
data: Data ← GetData[ctx];
device: CGDevice.Ref ← ctx.device;
cp: Vec ← ctx.cp;
src: CGSource.Ref ← ctx.src;
T: CGMatrix.Ref ← ctx.matrix;
M: CGMatrix.Ref ← data.map;
mask: CGSource.Ref ← data.mask;

IF data.lastid#T.id THEN {
CGMatrix.Assign[M,T];
IF ctx.yUp THEN CGMatrix.Concat[M,1,0,0,-1];
data.lastid ← T.id };

IF base=NIL THEN { [base: base, raster: raster] ← CGScreen.Bits[] };
mask.xbase ← base; mask.xrast ← raster; mask.bps ← bitsPerPixel;
mask.type ← array; mask.mode ← src.mode; mask.color ← src.color;
mask.raw ← (bitsPerPixel#0); -- crock!
CGMatrix.SetTrans[M,cp];
CGMatrix.Translate[M,-xorigin,-yorigin];

{ box: Box ← [xmin: x, xmax: x+w, ymin: y, ymax: y+h];
area: CGArea.Ref ← CGContext.GenBox[ctx,box,M];
device.Show[device,area,mask,M];
};

};

SetTargetBitmap: PUBLIC PROC[self: Context, bitmap: BitmapRef] = {
ctx: ContextData ← NARROW[self.data];
device: CGDevice.Ref ← IF bitmap=NIL
THEN CGBitmapDevice.New[NIL,0,0]
ELSE CGBitmapDevice.New[
base: bitmap.base, raster: bitmap.raster, height: bitmap.height];
m: CGMatrix.Ref ← device.GetMatrix[device];
dbase: LONG POINTERNIL; drast: CARDINAL ← 0;
ctx.device ← device;
CGMatrix.Assign[ctx.matrix,m];
ctx.yUp ← TRUE;
ctx.cp ← CGMatrix.Map[m,[0,0]];
CGClipper.SetBox[ctx.clipper,device.GetBounds[device]];
ctx.src^ ← [type: const, fat: FALSE, mode: opaque,
bps: 0, color: GraphicsBasic.black, xbase: NIL, xrast: 0, Get: NIL];
ctx.boxing ← ctx.newbox ← FALSE;
IF device.GetRaster#NIL THEN { [dbase,drast] ← device.GetRaster[device] };
IF dbase=NIL THEN { ctx.dbase ← NIL; ctx.drast ← 0; ctx.haveRaster ← FALSE }
ELSE { ctx.dbase ← dbase; ctx.drast ← drast; ctx.haveRaster ← TRUE };
CGContext.ResetPool[ctx];
};

NewBitmap: PUBLIC PROC[width,height: CARDINAL] RETURNS[BitmapRef] = {
Words: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF CARDINAL];
raster: CARDINAL = (width+15)/16;
base: REF ← bitmapZone.NEW[Words[raster*height]];
RETURN[repZone.NEW[BitmapRep ← [base: base, raster: raster, width: width, height: height]]];
};

ScreenBitmap: PUBLIC PROC RETURNS[BitmapRef] = {
raster,height: CARDINAL;
[raster: raster, height: height] ← CGScreen.Bits[];
RETURN[repZone.NEW[BitmapRep ← [
base: NIL, raster: 0, -- Convention: NIL means the screen
width: 16*raster, height: height]]];
};

DrawTexturedBox: PUBLIC PROC[self: Context, box: Box, texture: GraphicsOps.Texture] = {
ctx: ContextData ← NARROW[self.data];
data: Data ← GetData[ctx];
device: CGDevice.Ref ← ctx.device;
src: CGSource.Ref ← data.mask;

TRUSTED { src.xbase ← @texture };
src.xrast ← 1;
src.type ← tile;
src.mode ← ctx.src.mode;
src.color ← ctx.src.color;
{ area: CGArea.Ref ← CGContext.GenBox[ctx, box, ctx.matrix];
device.Show[device, area, src, NIL] };

};


}.