-- ColorDeviceImpl.mesa -- Last changed by Ken Pier July 11, 1983 12:05 pm -- Last changed by Maureen Stone October 18, 1982 1:26 pm -- Last changed by Doug Wyatt, September 1, 1982 3:50 pm DIRECTORY ColorDisplay, GraphicsBasic USING [Box, Color, Trap, Vec], GraphicsColor USING [blue, cyan, green, magenta, red, white, yellow], CGArea USING [Empty, Ref, Remove], ColorDevice USING [], -- only for EXPORTS CGDevice USING [Ref, Rep], CGMatrix USING [Inv, InvRel, IsTrivial, Make, Ref], CGSource USING [Mode, Ref, Type], CGStorage USING [qZone], ColorMap USING [GetGrayTable, GrayTable, GetIndex, GrayRec], CGColor USING [GetStipple], Inline USING [BITAND, BITOR, BITSHIFT, BITXOR, HighHalf, LongMult, LongNumber, LowByte, LowHalf], BitBlt, Real USING [Fix, FixC, RoundC]; ColorDeviceImpl: MONITOR IMPORTS CGArea, CGColor, CGMatrix, CGStorage, BitBlt, Inline, Real, CD: ColorDisplay, ColorMap EXPORTS ColorDevice, GraphicsBasic = { OPEN Area: CGArea, Matrix: CGMatrix, Source: CGSource, CGDevice, GraphicsBasic; DeviceObject: PUBLIC TYPE = CGDevice.Rep; -- exported to GraphicsBasic Byte: TYPE = [0..256); dataZone: ZONE = CGStorage.qZone; repZone: ZONE = CGStorage.qZone; Error: PUBLIC SAFE ERROR = CODE; bbspace: BitBlt.BBTableSpace; bb: BitBlt.BitBltTablePtr _ BitBlt.AlignedBBTable[@bbspace]; Data: TYPE = REF DataRep; DataRep: TYPE = RECORD [ width,height: CARDINAL _ 0, grayTable: ColorMap.GrayTable _ NIL, lastColor: Color _ [tag: rgb, r: 0, g: 0, b: 0], lastPixel: LONG CARDINAL, stipple: CARDINAL _ 0, --base and words per line all available thru ColorDisplay matrix: Matrix.Ref _ NIL -- base transformation matrix ]; New: PUBLIC SAFE PROC[raster, height: CARDINAL _ 0] RETURNS[CGDevice.Ref] = CHECKED { data: Data _ dataZone.NEW[DataRep]; IF raster = 0 THEN data.width _ CD.width ELSE data.width _ raster; IF height = 0 THEN data.height _ CD.height ELSE data.height _ height; data.grayTable _ ColorMap.GetGrayTable[]; data.matrix _ Matrix.Make[[1,0,0,-1,0,data.height]]; --should be a function of pixelsPerInch RETURN[repZone.NEW[CGDevice.Rep _ [ GetMatrix: GetMatrix, GetBounds: GetBounds, Show: Show, GetRaster: GetRaster, MoveBlock: MoveBlock, data: data]]]; }; GetMatrix: SAFE PROC[self: Ref] RETURNS[Matrix.Ref] = CHECKED { data: Data _ NARROW[self.data]; RETURN[data.matrix]; }; GetBounds: SAFE PROC[self: Ref] RETURNS[Box] = CHECKED { data: Data _ NARROW[self.data]; w: CARDINAL _ data.width; h: CARDINAL _ data.height; e: REAL = 0.1; -- small fudge factor RETURN[[xmin: e, ymin: e, xmax: w-e, ymax: h-e]]; }; --bitmap speedup hack, not valid for color display GetRaster: SAFE PROC[self: Ref] RETURNS[LONG POINTER,CARDINAL] = CHECKED { RETURN[NIL,0] }; Show: ENTRY SAFE PROC[self: Ref, area: Area.Ref, src: Source.Ref, map: Matrix.Ref] = TRUSTED { data: Data _ NARROW[self.data]; bitmap: BOOLEAN _ (src.type=array AND src.bps=0 AND CGMatrix.IsTrivial[map]); invertHack: LONG CARDINAL _ data.lastPixel; IF CD.curmode=CD.disconnected THEN RETURN; --colordisplay is disconnected IF src.mode=invert THEN { IF CD.curmode.full THEN data.lastPixel _ -1 ELSE data.lastPixel _ 255} ELSE SetColor[data,src.color]; --sets up the values for color IF NOT CD.curmode.full AND src.bps >0 AND ~src.raw THEN SetGrayTable[data,src.bps]; --sets up a lookup table for source grays UNTIL Area.Empty[area] DO trap: Trap _ Area.Remove[area]; IF bitmap AND trap.xbotL=trap.xtopL AND trap.xbotR=trap.xtopR THEN { box: GraphicsBasic.Box _ [trap.xbotL, trap.ybot, trap.xbotR, trap.ytop]; ShowBitmap[data,box,src,map] } ELSE ShowTrap[data,trap,src,map]; ENDLOOP; IF src.mode=invert THEN data.lastPixel _ invertHack; }; SetColor: PROC [data: Data, color: GraphicsBasic.Color] = { IF color = data.lastColor THEN RETURN; IF color.tag = stipple THEN data.stipple _ CGColor.GetStipple[color]; IF CD.curmode.full THEN data.lastPixel _ Pack[color.r,color.g,color.b] ELSE data.lastPixel _ ColorMap.GetIndex[color.r,color.g,color.b]; data.lastColor _ color; }; SetGrayTable: PROC [data: Data, srcBps: CARDINAL] = { cmapGrays: ColorMap.GrayTable _ ColorMap.GetGrayTable[]; slen: REAL _ TwoToThe[srcBps]; scaler: REAL _ 255.0/(slen-1); IF data.grayTable=NIL OR data.grayTable.length#slen THEN data.grayTable _ NEW[ColorMap.GrayRec[TwoToThe[srcBps]]]; FOR i: CARDINAL IN [0..data.grayTable.length) DO data.grayTable[i] _ cmapGrays[Real.RoundC[i*scaler]]; ENDLOOP; }; --v is assumed to be 8 bps or less TwoToThe: PROC[power: INTEGER] RETURNS[INTEGER] = { RETURN[Inline.BITSHIFT[value: 2, count: power-1]]; }; GetBBColor: PROC[color: CARDINAL, bps: CARDINAL] RETURNS [CARDINAL] = { grey,temp: CARDINAL _ 0; IF color#0 THEN { SELECT bps FROM 1 => temp _ Inline.BITAND[color,mask1]; 2 => temp _ Inline.BITAND[color,mask2]; 4 => temp _ Inline.BITAND[color,mask4]; 8 => temp _ Inline.BITAND[color,mask8]; ENDCASE => ERROR Error; FOR b: CARDINAL IN [0..16/bps) DO grey _ Inline.BITOR[temp,grey]; temp _ Inline.BITSHIFT[temp,bps]; ENDLOOP; }; RETURN[grey]; }; Line1: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..1B]]; Line2: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..3B]]; Line4: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..17B]]; Line8: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..377B]]; Line16: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF CARDINAL]; --these routines put stuff in the bitmap --assume that s is already masked Put: PROC[dbase: LONG POINTER, drast: CARDINAL, x,y: CARDINAL, v: LONG CARDINAL] = { xline: LONG POINTER _ dbase + Inline.LongMult[y,drast]; IF CD.curmode.full THEN { pair: CD.Pair _ Inline.LowHalf[v]; blue: Byte _ Inline.LowByte[Inline.HighHalf[v]]; CD.SetPixel[x,y,pair.r,pair.g,blue]; } ELSE { short: CARDINAL _ Inline.LowHalf[v]; SELECT CD.curmode.bitsPerPixelA FROM 1 => LOOPHOLE[xline,LONG POINTER TO Line1][x] _ Inline.BITAND[short,mask1]; 2 => LOOPHOLE[xline,LONG POINTER TO Line2][x] _ Inline.BITAND[short,mask2]; 4 => LOOPHOLE[xline,LONG POINTER TO Line4][x] _ Inline.BITAND[short,mask4]; 8 => LOOPHOLE[xline,LONG POINTER TO Line8][x] _ Inline.BITAND[short,mask8]; ENDCASE => ERROR Error; }; }; --"transparent mode" Transparent: PROC[dbase: LONG POINTER, drast: CARDINAL, x,y: CARDINAL, value: LONG CARDINAL] = { xline: LONG POINTER _ dbase + Inline.LongMult[y,drast]; IF CD.curmode.full THEN { pair: CD.Pair _ Inline.LowHalf[value]; blue: Byte _ Inline.LowByte[Inline.HighHalf[value]]; r,g,b: Byte; [r,g,b] _ CD.GetPixel[x,y]; pair.r _ MIN[pair.r+r,255]; pair.g _ MIN[pair.g+g,255]; blue _ MIN[blue+b,255]; CD.SetPixel[x,y,pair.r,pair.g,blue]; } ELSE SELECT CD.curmode.bitsPerPixelA FROM 1 => IF value=1 THEN LOOPHOLE[xline,LONG POINTER TO Line1][x] _ value; 2 => {v: CARDINAL _ LOOPHOLE[xline,LONG POINTER TO Line2][x]; v _ MIN[v+value,3]; LOOPHOLE[xline,LONG POINTER TO Line2][x] _ v}; 4 => {v: CARDINAL _ LOOPHOLE[xline,LONG POINTER TO Line4][x]; v _ MIN[v+value,15]; LOOPHOLE[xline,LONG POINTER TO Line4][x] _ v}; 8 => {v: CARDINAL _ LOOPHOLE[xline,LONG POINTER TO Line8][x]; v _ MIN[v+value,255]; LOOPHOLE[xline,LONG POINTER TO Line8][x] _ v}; ENDCASE => ERROR Error; }; --"invert mode" Invert: PROC[dbase: LONG POINTER, drast: CARDINAL, x,y: CARDINAL] = { xline: LONG POINTER _ dbase + Inline.LongMult[y,drast]; IF CD.curmode.full THEN { r,g,b: Byte; temp: Byte _ 377B; [r,g,b] _ CD.GetPixel[x,y]; r _ Inline.BITXOR[temp,r]; g _ Inline.BITXOR[temp,g]; b _ Inline.BITXOR[temp,b]; CD.SetPixel[x,y,r,g,b]; } ELSE { temp: CARDINAL _ 177777B; SELECT CD.curmode.bitsPerPixelA FROM 1 => {v: CARDINAL _ LOOPHOLE[xline,LONG POINTER TO Line1][x]; v _ Inline.BITXOR[v,temp]; v _ Inline.BITAND[v,mask1]; LOOPHOLE[xline,LONG POINTER TO Line2][x] _ v}; 2 => {v: CARDINAL _ LOOPHOLE[xline,LONG POINTER TO Line2][x]; v _ Inline.BITXOR[v,temp]; v _ Inline.BITAND[v,mask2]; LOOPHOLE[xline,LONG POINTER TO Line2][x] _ v}; 4 => {v: CARDINAL _ LOOPHOLE[xline,LONG POINTER TO Line4][x]; v _ Inline.BITXOR[v,temp]; v _ Inline.BITAND[v,mask4]; LOOPHOLE[xline,LONG POINTER TO Line4][x] _ v}; 8 => {v: CARDINAL _ LOOPHOLE[xline,LONG POINTER TO Line8][x]; v _ Inline.BITXOR[v,temp]; v _ Inline.BITAND[v,mask8]; LOOPHOLE[xline,LONG POINTER TO Line8][x] _ v}; ENDCASE => ERROR Error; }; }; --this gets a source sample from an array of values AGet: PROC[src: Source.Ref, x,y: CARDINAL] RETURNS[value: LONG CARDINAL] = { xline: LONG POINTER _ src.xbase + Inline.LongMult[y,src.xrast]; SELECT src.bps FROM 0 => value _ LOOPHOLE[xline,LONG POINTER TO Line1][x]; 1 => value _ LOOPHOLE[xline,LONG POINTER TO Line1][x]; 2 => value _ LOOPHOLE[xline,LONG POINTER TO Line2][x]; 4 => value _ LOOPHOLE[xline,LONG POINTER TO Line4][x]; 8 => value _ LOOPHOLE[xline,LONG POINTER TO Line8][x]; ENDCASE => ERROR Error; }; mask1: CARDINAL = 1B; mask2: CARDINAL = 3B; mask4: CARDINAL = 17B; mask8: CARDINAL = 377B; --this converts from a bps bit array value to a 24 bps color FullTint: PROC[in: LONG CARDINAL, bps: INTEGER, color: GraphicsBasic.Color] RETURNS[out: LONG CARDINAL] = {OPEN GraphicsColor; intensity: REAL _ REAL[in]/(TwoToThe[bps]); v: Byte _ Real.RoundC[intensity*255]; SELECT color FROM red => out _ Pack[v,0,0]; green => out _ Pack[0,v,0]; blue => out _ Pack[0,0,v]; magenta => out _ Pack[v,0,v]; cyan => out _ Pack[0,v,v]; yellow => out _ Pack[v,v,0]; white => out _ Pack[v,v,v]; ENDCASE => { ir: Byte _ Real.RoundC[intensity*color.r]; ig: Byte _ Real.RoundC[intensity*color.g]; ib: Byte _ Real.RoundC[intensity*color.b]; out _ Pack[ir,ig,ib]; }; RETURN[out]; }; white: LONG CARDINAL _ Pack[377B,377B,377B]; black: LONG CARDINAL _ 0; Pack: PROC[r,g,b: Byte] RETURNS [LONG CARDINAL] = { rg: CD.Pair; out: Inline.LongNumber _ [num[0,0]]; rg.r _ r; rg.g _ g; out.lowbits _ LOOPHOLE[rg,CARDINAL]; out.highbits _ LOOPHOLE[b,CARDINAL]; RETURN[out.lc]; }; Masks: TYPE = ARRAY [0..16) OF WORD; masksArray: Masks _ [ 100000B, 040000B, 020000B, 010000B, 004000B, 002000B, 001000B, 000400B, 000200B, 000100B, 000040B, 000020B, 000010B, 000004B, 000002B, 000001B]; masks: POINTER TO Masks _ @masksArray; ShowBitmap: PROC[data: Data, rect: Box, src: CGSource.Ref, map: CGMatrix.Ref] = { type: CGSource.Type _ src.type; mode: CGSource.Mode _ src.mode; xmin, xmax, ymin, ymax: NAT; xmin _ Rnd[rect.xmin]; xmax _ Rnd[rect.xmax]; ymin _ Rnd[rect.ymin]; ymax _ Rnd[rect.ymax]; IF NOT(xminxmin AND cxminymin AND cymin