<> <> <> <> <<>> <> DIRECTORY CD USING [LayerKey, Object, Position, undefLayer], CDBasics USING [BaseOfRect, ComposeTransform, MapRect, NonEmpty, SizeOfRect], CDColors USING [ColorTable, DisplayMode, DisplayType, globalColors], Checksum USING [ComputeChecksum], Core USING [CellType, Wire], CoreClasses USING [CellInstance, recordCellClass, RecordCellType, transistorCellClass], CoreGeometry USING [BBox, CellInstance, CellType, Decoration, EachInstanceProc, EnumerateGeometry, FlattenInstance, GetObject, GetTrans, Instance, Layer, Transformation, Wire], CoreOps USING [GetCellTypeName], CoreView USING [CoreCell, Layout, Rect, Viewer], CStitching USING [all, Area, ChangeEnumerateArea, ChangeRect, DumpCache, EnumerateArea, NewTesselation, RectProc, Region, ResetTesselation, Tesselation, Tile, TileProc], Cursors USING [CursorType], HashTable USING [Create, EachPairAction, Fetch, Insert, Key, Pairs, Table], Icons USING [NewIconFromFile], Imager USING [black, ClipRectangle, Color, Context, ConstantColor, Font, MakeGray, MaskRectangle, MaskVectorI, Rectangle, ScaleT, SetColor, SetFont, SetPriorityImportant, SetStrokeEnd, SetStrokeJoint, SetStrokeWidth, SetXY, ShowRope, TranslateT, VEC, white], ImagerBackdoor USING [GetBounds], ImagerColor USING [ColorFromRGB, RGB], ImagerColorPrivate USING [ComponentFromColor], ImagerTransformation USING [Transformation], IO USING [card, int, PutR1], Menus USING [AppendMenuEntry, ClickProc, CreateEntry, CreateMenu, Menu, MenuEntry], MessageWindow USING [Append, Blink, Clear], Real USING [FixI, Float], Rope USING [Cat, ROPE], VFonts USING [defaultFont], ViewerClasses USING [DestroyProc, HScrollProc, PaintProc, ScrollProc, ViewerClass, ViewerClassRec, ViewerFlavor, ViewerRec], ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass], WindowManager USING [colorDisplayOn]; CoreViewImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDColors, Checksum, CoreGeometry, CoreOps, CoreClasses, CStitching, HashTable, Icons, Imager, ImagerBackdoor, ImagerColor, ImagerColorPrivate, IO, Menus, MessageWindow, Real, Rope, VFonts, ViewerOps, WindowManager EXPORTS CoreView ~ BEGIN OPEN CoreView, Real; break: SIGNAL ~ CODE; -- for debugging Font: TYPE ~ Imager.Font; Color: TYPE ~ Imager.Color; Context: TYPE ~ Imager.Context; Rectangle: TYPE ~ Imager.Rectangle; Transformation: TYPE ~ ImagerTransformation.Transformation; ROPE: TYPE ~ Rope.ROPE; Region: TYPE ~ LIST OF REF CStitching.Region; Tess: TYPE ~ CStitching.Tesselation; Tile: TYPE ~ CStitching.Tile; Transf: TYPE ~ CoreGeometry.Transformation; CoreInst: TYPE ~ CoreGeometry.CellInstance; FakeInst: TYPE ~ CoreGeometry.Instance; Wire: TYPE ~ CoreGeometry.Wire; Layer: TYPE ~ CoreGeometry.Layer; debugViewer: PUBLIC Viewer; identity: Transf; -- READONLY it is the default rectClass: ATOM ~ $Rect; markClass: ATOM ~ $AlignmentMarkOb; segmentClass: ATOM ~ $SymbolicSegment; pinClass: ATOM ~ $PinOb0; empty: REF ~ NIL; nothing: REF INT ~ NEW [INT]; State: TYPE = REF StateRec; StateRec: TYPE = RECORD [ previousColour: Color _ NIL, tess: Tess, boundingBox, window: Rectangle, translation: Imager.VEC _ [0.0, 0.0], -- initialization imporant for caches scale: REAL, bottomSB, rightSB: INTEGER _ 100, -- caches: initialization imporant topSB, leftSB: INTEGER _ 0, -- caches: initialization imporant resetPainting: BOOL _ TRUE, -- initialization imporant for caches attributes: Layout, abort: REF BOOL]; <> GeometryView: PUBLIC PROC [cell: CoreCell, geom: Layout, abortFlag: REF BOOL] RETURNS [viewer: Viewer] ~ BEGIN <> state: State ~ NEW [StateRec]; BEGIN OPEN state; abort _ IF (abortFlag # NIL) THEN abortFlag ELSE NEW [BOOL _ FALSE]; boundingBox _ window _ ImagerRect [CoreGeometry.BBox [[CoreGeometry.GetObject [geom, cell], identity]]]; tess _ CStitching.NewTesselation [stopFlag: abort]; previousColour _ NIL; attributes _ geom END; viewer _ InitializeViewer [cell, normal, state]; IF (EnumerateCore [cell, identity, EveryCell, state]) THEN RETURN; SetLayerColourTable; BlendAllColours; ViewerOps.PaintViewer [viewer: viewer, hint: client] END; -- GeometryView StartIncrementalView: PUBLIC PROC [cell: CoreCell, geom: Layout, abortFlag: REF BOOL] RETURNS [viewer: Viewer] ~ BEGIN <> state: State ~ NEW [StateRec]; BEGIN OPEN state; abort _ IF (abortFlag # NIL) THEN abortFlag ELSE NEW [BOOL _ FALSE]; boundingBox _ window _ ImagerRect [CoreGeometry.BBox [[CoreGeometry.GetObject [geom, cell], identity]]]; tess _ CStitching.NewTesselation [stopFlag: abort]; previousColour _ NIL; attributes _ geom END; viewer _ InitializeViewer [cell, labelled, state]; END; -- StartIncrementalView AddRectangle: PUBLIC PROC [viewer: Viewer, rect: Rect, label: REF ANY] ~ BEGIN <> state: State ~ NARROW [viewer.data]; InsertRect: CStitching.RectProc ~ BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]>> plane.ChangeRect [rect: rect, new: label] END; -- InsertRect IF state.abort^ THEN RETURN; state.tess.ChangeEnumerateArea [rect: rect, eachRect: InsertRect, skip: nothing]; ViewerOps.PaintViewer [viewer: viewer, hint: client] END; -- AddRectangle <> ComposedTransf: PROC [parent: Transf, child: CoreInst, state: State] RETURNS [Transf] ~ BEGIN <> RETURN [CDBasics.ComposeTransform [CoreGeometry.GetTrans [state.attributes, child], parent]] END; -- ComposedTransf EachCell: TYPE ~ PROC [cell: CoreCell, transf: Transf, state: State]; EnumerateCore: PROC [cell: CoreCell, transf: Transf, action: EachCell, state: State] RETURNS [quit: BOOL _ FALSE] ~ BEGIN <> IF state.abort^ THEN RETURN [TRUE]; SELECT cell.class FROM CoreClasses.recordCellClass => BEGIN cellData: CoreClasses.RecordCellType ~ NARROW [cell.data]; FOR sub: NAT IN [0 .. cellData.size) DO subTransf: Transf ~ ComposedTransf [transf, cellData.instances[sub], state]; IF (EnumerateCore [cellData.instances[sub].type, subTransf, action, state]) THEN RETURN [TRUE] ENDLOOP END; ENDCASE => NULL; action [cell, transf, state]; quit _ state.abort^ END; -- EnumerateCore EveryCell: EachCell ~ BEGIN <<[cell: CoreCell, transf: Transf, state: State]>> SELECT cell.class FROM CoreClasses.recordCellClass => BEGIN cellData: CoreClasses.RecordCellType ~ NARROW [cell.data]; FOR i: NAT IN [0 .. cellData.internal.size) DO IF state.abort^ THEN RETURN; EveryWire [state: state, cell: cell, w: cellData.internal[i], transf: transf] ENDLOOP END; CoreClasses.transistorCellClass => EveryWire [cell, cell.public, transf, state]; ENDCASE => NULL; -- Print warning END; -- EveryCell EveryWire: PROC [cell: CoreCell, w: Wire, transf: Transf, state: State] ~ BEGIN EveryRect: CoreGeometry.EachInstanceProc ~ BEGIN <<[instance: CdInsts] RETURNS [quit: BOOL _ FALSE]>> rect: Rect ~ CDBasics.MapRect [CoreGeometry.BBox [instance], transf]; dec: Tess ~ state.tess; l: Layer ~ instance.obj.layer; InsertRect: CStitching.RectProc ~ BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]>> <> WITH oldValue SELECT FROM b: Blend => IF NOT b.flavours[l] THEN dec.ChangeRect [rect: rect, new: ColourTile [b, l]]; ENDCASE => BEGIN b: Blend _ NEW [BlendRec]; dec.ChangeRect [rect: rect, new: ColourTile [b, l]] END END; -- InsertRect IF state.abort^ THEN RETURN [state.abort^]; <> SELECT instance.obj.class.objectType FROM rectClass => IF (CDBasics.NonEmpty [rect]) THEN dec.ChangeEnumerateArea [rect: rect, eachRect: InsertRect, skip: nothing]; markClass, segmentClass, pinClass => NULL; ENDCASE => quit _ CoreGeometry.FlattenInstance [instance, EveryRect]; END; -- EveryRect [] _ state.attributes.EnumerateGeometry [w, EveryRect] END; -- EveryWire <> ViewerFlavor: TYPE ~ ViewerClasses.ViewerFlavor; normal: ViewerFlavor ~ $CoreView; labelled: ViewerFlavor ~ $LabelledCoreView; InitializeViewerClasses: PROC ~ BEGIN <> classN: ViewerClasses.ViewerClass _ NEW [ViewerClasses.ViewerClassRec]; classL: ViewerClasses.ViewerClass _ NEW [ViewerClasses.ViewerClassRec]; classMenu: Menus.Menu ~ Menus.CreateMenu []; abortButton: Menus.MenuEntry ~ Menus.CreateEntry [name: "Abort", proc: Abort, guarded: TRUE]; zoomInButton: Menus.MenuEntry ~ Menus.CreateEntry [name: "Zoom-In", proc: ZoomIn]; zoomOutButton: Menus.MenuEntry ~ Menus.CreateEntry [name: "Zoom-Out", proc: ZoomOut]; everythingButton: Menus.MenuEntry ~ Menus.CreateEntry [name: "Reset", proc: Everything]; classMenu.AppendMenuEntry [abortButton]; classMenu.AppendMenuEntry [zoomInButton]; classMenu.AppendMenuEntry [zoomOutButton]; classMenu.AppendMenuEntry [everythingButton]; BEGIN OPEN classN; flavor _ normal; paint _ Paint; destroy _ Destroy; scroll _ VerticalTranslation; hscroll _ HorizontalTranslation; menu _ classMenu; icon _ Icons.NewIconFromFile ["[DATools]CoreView>CoreView.Icon", 0]; cursor _ crossHairsCircle END; classL^ _ classN^; classL.flavor _ labelled; classL.icon _ Icons.NewIconFromFile ["[DATools]CoreView>CoreView.Icon", 1]; ViewerOps.RegisterViewerClass [normal, classN]; ViewerOps.RegisterViewerClass [labelled, classL] END; -- InitializeViewerClasses InitializeViewer: PROC [cell: CoreCell, flavor: ViewerFlavor, state: State] RETURNS [viewer: Viewer] ~ BEGIN <> info: ViewerClasses.ViewerRec; BEGIN OPEN info; label _ CoreOps.GetCellTypeName [cell]; name _ IF (flavor = normal) THEN label ELSE label.Cat [" debugging"]; column _ IF WindowManager.colorDisplayOn THEN color ELSE left; scrollable _ TRUE; hscrollable _ TRUE; iconic _ (flavor = labelled); guardDestroy _ TRUE; data _ state END; viewer _ ViewerOps.CreateViewer [flavor, info] END; -- InitializeViewer Paint: ViewerClasses.PaintProc ~ BEGIN <<[self: Viewer, context: Imager.Context, whatChanged: REF, clear: BOOL] RETURNS [quit: BOOL _ FALSE]>> <> state: State ~ NARROW [self.data]; ChangeColour: PROC [colour: Color] ~ INLINE BEGIN <> a: ImagerColor.RGB ~ RGBFromColour [colour]; b: ImagerColor.RGB ~ RGBFromColour [state.previousColour]; IF (a.R # b.R) OR (a.G # b.G) OR (a.B # b.B) OR (state.previousColour = NIL) THEN BEGIN <> IF (a.R = 0.0) AND (a.G = 0.0) AND (a.B = 0.0) THEN context.SetColor [blackBlack] ELSE context.SetColor [colour]; state.previousColour _ colour END END; -- ChangeColour PrintTile: CStitching.TileProc ~ BEGIN <> b: Blend ~ NARROW [tile.value]; r: Rect ~ CStitching.Area [tile]; -- not the area but the rectangle ! IF state.abort^ THEN RETURN; ChangeColour [b.blend]; context.MaskRectangle [ImagerRect [r]] END; -- PrintTile PrintLabeledTile: CStitching.TileProc ~ BEGIN <> r: Rect ~ CStitching.Area [tile]; -- not the area but the rectangle ! l: CARD; IF state.abort^ THEN RETURN; ChangeColour [lightGrey]; context.MaskRectangle [ImagerRect [r]]; ChangeColour [blackBlack]; context.SetStrokeWidth [0.0]; context.MaskVectorI [r.x1, r.y1, r.x2, r.y1]; -- South context.MaskVectorI [r.x2, r.y1, r.x2, r.y2]; -- East context.MaskVectorI [r.x2, r.y2, r.x1, r.y2]; -- North context.MaskVectorI [r.x1, r.y2, r.x1, r.y1]; -- West TRUSTED {l _ LOOPHOLE [tile.value, CARD]}; context.SetXY [[r.x1, r.y1]]; context.ShowRope [IO.PutR1 [IO.card [l]]] END; -- PrintLabeledTile state.abort^ _ FALSE; state.previousColour _ NIL; state.window _ ImagerBackdoor.GetBounds [context]; -- needed for scroll bars IF (self.class.flavor = normal) AND ((self.column = color) OR (NOT clear)) THEN BEGIN context.SetColor [IF (self.column = color) THEN grey ELSE whiteWhite]; context.MaskRectangle [state.window] END; IF state.abort^ THEN {state.abort^ _ FALSE; RETURN [TRUE]}; context.SetPriorityImportant [FALSE]; IF state.resetPainting THEN BEGIN -- important for initialization of caches state.translation _ [state.boundingBox.x, state.boundingBox.y]; state.scale _ MIN [(state.window.w / state.boundingBox.w), (state.window.h / state.boundingBox.h)]; state.resetPainting _ FALSE END; context.TranslateT [state.translation]; context.ScaleT [state.scale]; state.window _ ImagerBackdoor.GetBounds [context]; -- needed for scroll bars context.ClipRectangle [state.window]; context.SetStrokeJoint [mitered]; context.SetStrokeWidth [0]; context.SetStrokeEnd [square]; context.SetFont [VFonts.defaultFont]; SELECT self.class.flavor FROM normal => state.tess.EnumerateArea [rect: CStitching.all, eachTile: PrintTile, data: state, skip: empty]; labelled => state.tess.EnumerateArea [rect: CStitching.all, eachTile: PrintLabeledTile, data: state, skip: empty]; ENDCASE => ERROR END; -- Paint VerticalTranslation: ViewerClasses.ScrollProc ~ BEGIN <<[self: Viewer, op: ScrollOp, amount: INTEGER, shift, control: BOOL _ FALSE] RETURNS [top, bottom: INTEGER _ LAST[INTEGER]]>> <> <> state: State ~ NARROW [self.data]; <> BEGIN OPEN state; SELECT op FROM query => BEGIN <> top _ MAX [topSB, 0]; bottom _ MIN [bottomSB, 100]; RETURN END; up => IF (window.y < boundingBox.y+boundingBox.h) THEN BEGIN translation.y _ translation.y + (Float [amount] / Float [self.ch]) * window.h; <> <> topSB _ FixI [(window.y + window.h) / (boundingBox.y + boundingBox.h) * 100.0]; bottomSB _ topSB + FixI [(window.h / boundingBox.h) * 100.0] END; down => IF (window.y+window.h > boundingBox.y) THEN BEGIN translation.y _ translation.y - (Float [amount] / Float [self.ch]) * window.h; topSB _ FixI [(window.y + window.h) / (boundingBox.y + boundingBox.h) * 100.0]; bottomSB _ topSB + FixI [(window.h / boundingBox.h) * 100.0] END; thumb => SELECT TRUE FROM shift AND control => ImportantMessage ["Invalid command"]; shift => BEGIN -- scale up (window becomes relatively smaller) <> factor: REAL ~ 10.0 / Float [amount + 10]; scale _ scale * factor; topSB _ FixI [((window.y + window.h) * factor) / (boundingBox.y + boundingBox.h) * 100.0]; bottomSB _ topSB + FixI [(window.h / boundingBox.h) * 100.0] END; control => BEGIN -- reset painting resetPainting _ TRUE; bottomSB _ rightSB _ 100; topSB _ leftSB _ 0 END; ENDCASE => BEGIN -- thumb sign: INTEGER _ IF (boundingBox.h > window.h) THEN -1 ELSE 1; translation.y _ sign * (boundingBox.y + (boundingBox.h * Float [amount] / 100.0)); topSB _ amount; bottomSB _ amount + FixI [(window.h / boundingBox.h) * 100.0] END; ENDCASE => ERROR; Trace [amount]; ViewerOps.PaintViewer [viewer: self, hint: client]; -- op <> query <> top _ MAX [topSB, 0]; bottom _ MIN [bottomSB, 100] END -- OPEN state END; -- VerticalTranslation HorizontalTranslation: ViewerClasses.HScrollProc ~ BEGIN <<[self: Viewer, op: HScrollOp, amount: INTEGER, shift, control: BOOL _ FALSE] RETURNS [left, right: INTEGER _ LAST[INTEGER]]>> <> <> state: State ~ NARROW [self.data]; BEGIN OPEN state; SELECT op FROM query => BEGIN <> right _ MIN [rightSB, 100]; left _ MAX [leftSB, 0]; RETURN END; right => IF (window.x < boundingBox.x+boundingBox.w) THEN BEGIN translation.x _ translation.x + (Float [amount] / Float [self.cw]) * window.w; leftSB _ FixI [(window.x + window.w) / (boundingBox.x + boundingBox.w) * 100.0]; rightSB _ leftSB + FixI [(window.w / boundingBox.w) * 100.0] END; left => IF (window.x+window.w > boundingBox.x) THEN BEGIN translation.x _ translation.x - (Float [amount] / Float [self.cw]) * window.w; leftSB _ FixI [(window.x + window.w) / (boundingBox.x + boundingBox.w) * 100.0]; rightSB _ leftSB + FixI [(window.w / boundingBox.w) * 100.0] END; thumb => SELECT TRUE FROM shift AND control => ImportantMessage ["Invalid command"]; shift => BEGIN -- scale down (window becomes relatively larger) factor: REAL ~ Float [amount + 10] / 10.0; scale _ scale * factor; leftSB _ FixI [((window.x + window.w) * factor) / (boundingBox.x + boundingBox.w) * 100.0]; rightSB _ leftSB + FixI [(window.w / boundingBox.w) * 100.0] END; control => BEGIN -- reset painting resetPainting _ TRUE; bottomSB _ rightSB _ 100; topSB _ leftSB _ 0 END; ENDCASE => BEGIN -- thumb sign: INTEGER _ IF (boundingBox.w > window.w) THEN -1 ELSE 1; translation.x _ sign * (boundingBox.x + (boundingBox.w * Float [amount] / 100.0)); leftSB _ amount; rightSB _ amount + FixI [(window.w / boundingBox.w) * 100.0] END; ENDCASE => ERROR; Trace [amount]; ViewerOps.PaintViewer [viewer: self, hint: client]; -- op <> query <> right _ MIN [rightSB, 100]; left _ MAX [leftSB, 0] END -- OPEN state END; -- HorizontalTranslation Destroy: ViewerClasses.DestroyProc ~ BEGIN <> state: State ~ NARROW [self.data]; state.tess.ResetTesselation []; CStitching.DumpCache END; -- Destroy Abort: Menus.ClickProc ~ BEGIN <<[parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE]>> IF NOT ISTYPE [parent, Viewer] THEN ImportantMessage ["Implementation error"] ELSE BEGIN state: State ~ NARROW [NARROW [parent, Viewer].data]; state.abort^ _ TRUE END END; -- Abort ZoomIn: Menus.ClickProc ~ BEGIN <<[parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE]>> IF NOT ISTYPE [parent, Viewer] THEN ImportantMessage ["Implementation error"] ELSE BEGIN v: Viewer ~ NARROW [parent]; state: State ~ NARROW [v.data]; BEGIN OPEN state; scale _ scale * 1.5; ViewerOps.PaintViewer [viewer: v, hint: client]; topSB _ FixI [(window.y + window.h) / (boundingBox.y + boundingBox.h) * 100.0]; bottomSB _ topSB + FixI [(window.h / boundingBox.h) * 100.0]; leftSB _ FixI [(window.x + window.w) / (boundingBox.x + boundingBox.w) * 100.0]; rightSB _ leftSB + FixI [(window.w / boundingBox.w) * 100.0] END END END; -- ZoomIn ZoomOut: Menus.ClickProc ~ BEGIN <<[parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE]>> IF NOT ISTYPE [parent, Viewer] THEN ImportantMessage ["Implementation error"] ELSE BEGIN v: Viewer ~ NARROW [parent]; state: State ~ NARROW [v.data]; BEGIN OPEN state; scale _ scale / 1.5; ViewerOps.PaintViewer [viewer: v, hint: client]; topSB _ FixI [(window.y + window.h) / (boundingBox.y + boundingBox.h) * 100.0]; bottomSB _ topSB + FixI [(window.h / boundingBox.h) * 100.0]; leftSB _ FixI [(window.x + window.w) / (boundingBox.x + boundingBox.w) * 100.0]; rightSB _ leftSB + FixI [(window.w / boundingBox.w) * 100.0] END END END; -- ZoomOut Everything: Menus.ClickProc ~ BEGIN <<[parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE]>> IF NOT ISTYPE [parent, Viewer] THEN ImportantMessage ["Implementation error"] ELSE BEGIN v: Viewer ~ NARROW [parent]; state: State ~ NARROW [v.data]; state.resetPainting _ TRUE; SetLayerColourTable; BlendAllColours; state.bottomSB _ state.rightSB _ 100; state.topSB _ state.leftSB _ 0; ViewerOps.PaintViewer [viewer: v, hint: client] END END; -- Everything <> <> Bitset: TYPE ~ PACKED ARRAY Layer OF BOOLEAN _ ALL [FALSE]; BlendKey: TYPE ~ REF Bitset; Blend: TYPE ~ REF BlendRec; BlendRec: TYPE ~ RECORD [count: Layer _ 0, flavours: Bitset, blend: Color _ NIL, area: CARD _ 0]; colourTable: HashTable.Table ~ HashTable.Create [557, Match, Hash]; -- or 997 layerColorTable: ARRAY Layer OF Color; -- must be set for each task ColourTile: PROC [old: Blend, l: Layer] RETURNS [new: Blend] ~ BEGIN <> key: BlendKey ~ NEW [Bitset _ old.flavours]; key[l] _ TRUE; new _ NARROW [colourTable.Fetch[key].value, Blend]; IF (new = NIL) THEN BEGIN copy: Blend _ NEW [BlendRec _ [flavours: old.flavours]]; copy.count _ SUCC [old.count]; copy.flavours[l] _ TRUE; new _ copy; IF NOT colourTable.Insert [key, copy] THEN ERROR END END; -- ColourTile blackBlack: Color ~ Imager.black; whiteWhite: Color ~ Imager.white; grey: Color ~ Imager.MakeGray [0.36]; lightGrey: Color ~ Imager.MakeGray [0.18]; black: Color ~ ImagerColor.ColorFromRGB [[0.0, 0.0, 0.0]]; blue: Color ~ ImagerColor.ColorFromRGB [[0.0, 0.0, 1.0]]; unColour: ImagerColor.RGB ~ [0.0, 0.0, 0.0]; doubleYellowRGB: ImagerColor.RGB ~ [2.0, 2.0, 0.0]; magentaRGB: ImagerColor.RGB ~ [1.0, 0.0, 1.0]; cyan: Color ~ ImagerColor.ColorFromRGB [[0.0, 1.0, 1.0]]; lightYellow: Color ~ ImagerColor.ColorFromRGB [[6.0/7.0, 6.0/7.0, 3.0/7.0]]; lightMagenta: Color ~ ImagerColor.ColorFromRGB [[5.0/7.0, 0.0, 5.0/7.0]]; BlendColours: HashTable.EachPairAction ~ BEGIN <> <<[key: Key, value: Value] RETURNS [quit: BOOLEAN _ FALSE]>> components: Blend ~ NARROW [value]; n: REAL _ Float [components.count]; comp: PACKED ARRAY Layer OF BOOLEAN _ components.flavours; mix: ImagerColor.RGB _ unColour; IF (components.blend # NIL) THEN RETURN [FALSE]; -- caching across sessions SELECT n FROM 0 => ERROR; -- should never have been allocated 1 => BEGIN i: Layer _ 0; WHILE NOT comp[i] DO i _ SUCC [i] ENDLOOP; components.blend _ LayerColour [i] END; ENDCASE => BEGIN poly, diff, met, met2, cut, cut2, well: Layer _ 0; <> FOR i: Layer IN Layer DO IF comp[i] THEN SELECT CD.LayerKey[i] FROM $pol => poly _ i; $ndif, $pdif => diff _ i; $met => met _ i; $met2 => met2 _ i; $nwel => well _ i; $cut => cut _ i; $cut2 => {cut _ i; cut2 _ i}; ENDCASE => NULL ENDLOOP; <> IF (cut # 0) THEN components.blend _ IF (cut2 # 0) THEN blue ELSE black ELSE BEGIN -- Assume: all other colours have the same weight. IF (poly # 0) AND (diff # 0) THEN BEGIN -- Handle gates. <> mix _ doubleYellowRGB; comp[poly] _ comp[diff] _ FALSE END; IF (poly # 0) AND (met # 0) AND (diff = 0) THEN BEGIN -- Handle metal over poly. mix _ magentaRGB; n _ n - 1.0; comp[poly] _ comp[met] _ FALSE END; FOR i: Layer IN Layer DO -- Compute mean colour. IF comp[i] THEN BEGIN v: ImagerColor.RGB ~ RGBFromColour [LayerColour[i]]; mix.R _ mix.R + v.R; mix.G _ mix.G + v.G; mix.B _ mix.B + v.B END ENDLOOP; IF (met2 # 0) THEN BEGIN -- make metal-2 transparent mix.R _ mix.R - 4.0/7.0; mix.B _ mix.B - 4.0/7.0; n _ n - 4.0/7.0 END; IF (well # 0) THEN BEGIN -- make wells transparent mix.R _ mix.R - 5.0/7.0; mix.G _ mix.G - 5.0/7.0; n _ n - 5.0/7.0; mix.B _ mix.B - (3.0/7.0 * 2.0/7.0) -- take out well lightener END; mix.R _ mix.R / n; mix.G _ mix.G / n; mix.B _ mix.B / n; components.blend _ ImagerColor.ColorFromRGB [mix] END END; RETURN [FALSE] END; -- BlendColours LayerColour: PROC [l: Layer] RETURNS [Color] ~ INLINE BEGIN <> RETURN [layerColorTable[l]] END; -- LayerColour SetLayerColourTable: PROC ~ BEGIN <> FOR i: Layer IN Layer DO SELECT CD.LayerKey[i] FROM $nwel => layerColorTable[i] _ lightYellow; $met => layerColorTable[i] _cyan; $met2 => layerColorTable[i] _ lightMagenta; <> $cut => layerColorTable[i] _ black; $cut2 => layerColorTable[i] _ blue; ENDCASE => layerColorTable[i] _ CDColors.globalColors[bit8][normal].cols[i] ENDLOOP END; -- SetLayerColourTable BlendAllColours: PROC ~ BEGIN <> [] _ colourTable.Pairs [BlendColours] END; -- BlendAllColours Hash: PROC [k: HashTable.Key] RETURNS [CARDINAL] ~ BEGIN <> TRUSTED BEGIN RETURN [Checksum.ComputeChecksum [0, SIZE [BlendKey], LOOPHOLE [k]]] END END; -- Hash Match: PROC [a, b: HashTable.Key] RETURNS [BOOL] ~ BEGIN <> k1: BlendKey ~ NARROW [a, BlendKey]; k2: BlendKey ~ NARROW [b, BlendKey]; RETURN [(k1^ = k2^)] END; -- Match <> ImagerRect: PROC [r: Rect] RETURNS [Rectangle] ~ BEGIN base: CD.Position ~ CDBasics.BaseOfRect [r]; size: CD.Position ~ CDBasics.SizeOfRect [r]; RETURN [[Float[base.x], Float[base.y], Float[size.x], Float[size.y]]] END; -- ImagerRect ImagerVec: PROC [p: CD.Position] RETURNS [Imager.VEC] ~ BEGIN RETURN [[Float[p.x], Float[p.y]]] END; -- ImagerVec <> <> <> RGBFromColour: PROC [c: Color] RETURNS [rgb: ImagerColor.RGB] ~ INLINE BEGIN <> WITH c SELECT FROM constant: Imager.ConstantColor => BEGIN rgb.R _ ImagerColorPrivate.ComponentFromColor [constant, $Red]; rgb.G _ ImagerColorPrivate.ComponentFromColor [constant, $Green]; rgb.B _ ImagerColorPrivate.ComponentFromColor [constant, $Blue] END; ENDCASE => rgb _ unColour; RETURN [rgb] END; -- RGBFromColour ImportantMessage: PROC [msg: ROPE] ~ BEGIN <> MessageWindow.Clear []; MessageWindow.Append [msg]; MessageWindow.Blink [] END; -- ImportantMessage Trace: PROC [i: INTEGER] ~ BEGIN MessageWindow.Clear []; MessageWindow.Append [IO.PutR1 [IO.int [i]]] END; -- Trace <> InitializeViewerClasses END.