<> <> DIRECTORY Atom, G3dRender, G3dRenderWithImager, G3dClipXfmShade, G3dSortandDisplay, G3dVector, Imager, ImagerColor, ImagerColorFns, ImagerColorMap, ImagerFont, ImagerInterpress, ImagerPixel, IO, NamedColors, Real, Rope, ViewerClasses; G3dRenderWithImagerImpl: CEDAR MONITOR IMPORTS Atom, G3dRender, G3dClipXfmShade, G3dSortandDisplay, G3dVector, Imager, ImagerColor, ImagerColorFns, ImagerColorMap, ImagerFont, ImagerInterpress, ImagerPixel, IO, NamedColors, Real EXPORTS G3dRenderWithImager ~ BEGIN <> Context: TYPE ~ G3dRender.Context; ContextProc: TYPE ~ G3dRender.ContextProc; ContextClass: TYPE ~ G3dRender.ContextClass; ImagerProc: TYPE ~ G3dRender.ImagerProc; ImagerProcRec: TYPE ~ G3dRender.ImagerProcRec; Triple: TYPE ~ G3dRender.Triple; RGB: TYPE ~ G3dRender.RGB; Pixel: TYPE ~ G3dRender.Pixel; Rectangle: TYPE ~ G3dRender.Rectangle; Pair: TYPE ~ G3dRender.Pair; PairSequence: TYPE ~ G3dRender.PairSequence; IntegerPair: TYPE ~ G3dRender.IntegerPair; IntegerPairSequence: TYPE ~ G3dRender.IntegerPairSequence; IntRGB: TYPE ~ RECORD [r, g, b: CARDINAL]; IntRGBSequence: TYPE ~ RECORD [SEQUENCE length: NAT OF IntRGB]; NatSequence: TYPE ~ G3dRender.NatSequence; Patch: TYPE ~ G3dRender.Patch; PatchProc: TYPE ~ G3dRender.PatchProc; Shape: TYPE ~ G3dRender.Shape; RenderStyle: TYPE ~ G3dRender.RenderStyle; ClipState: TYPE ~ G3dRender.ClipState; ROPE: TYPE ~ Rope.ROPE; RopeProc: TYPE ~ G3dRender.RopeProc; PixelMap: TYPE ~ ImagerPixel.PixelMap; <> Ceiling: PROC[number: REAL] RETURNS[result: INTEGER] ~ { result _ Real.Round[number]; IF result < number THEN result _ result + 1; }; Floor: PROC[ in: REAL ] RETURNS[ out: INTEGER ] ~ { out _ Real.Round[in]; IF Real.Float[out] > in THEN out _ out - 1; }; FlushLog: PUBLIC PROC [context: Context] ~ { log: IO.STREAM _ NARROW[Atom.GetPropFromList[context.props, $Log]]; IF log # NIL THEN IO.Flush[log]; }; PairToScreen: PROC[context: Context, p: Pair] RETURNS[outP: Pair] ~ { outP.x _ context.ndcToPixels.scaleX * p.x + context.ndcToPixels.addX; outP.y _ context.ndcToPixels.scaleY * p.y + context.ndcToPixels.addY; }; <> Init: PROC[] ~ { -- register Imager-based drawing types standardClass: ContextClass _ [ displayType: $Bitmap, setUpDisplayType: SetUp, validateDisplay: ValidateDisplay, render: G3dSortandDisplay.MakeFrame, loadBackground: ClearViewPort, draw2DLine: Imager2DLine, draw2DPolygon: Imager2DPoly, draw2DRope: Draw2DRope, displayPolygon: ImagerPolygon ]; G3dRender.RegisterDisplayClass[ standardClass, $Bitmap ]; standardClass.displayType _ $ImagerGray; G3dRender.RegisterDisplayClass[ standardClass, $ImagerGray ]; standardClass.displayType _ $ImagerDithered; G3dRender.RegisterDisplayClass[ standardClass, $ImagerDithered ]; standardClass.displayType _ $ImagerFullClr; G3dRender.RegisterDisplayClass[ standardClass, $ImagerFullClr ]; standardClass.displayType _ $Interpress; standardClass.render _ MakePage; standardClass.loadBackground _ InterpressLoadBackground; G3dRender.RegisterDisplayClass[ standardClass, $Interpress ]; }; SetUp: ContextProc ~{ -- null procedure, Viewers & Imager do it all SELECT context.class.displayType FROM $ImagerGray => ImagerColorMap.SetStandardGrayMap[ context.terminal, ImagerColorMap.GetGamma[context.terminal] ]; $ImagerDithered => ImagerColorMap.SetStandardColorMap[ context.terminal, ImagerColorMap.GetGamma[context.terminal] ]; ENDCASE; -- don't do anything for $Bitmap, $ImagerFullClr, $Interpress }; ValidateDisplay: ContextProc ~{ -- update viewPort, etc. IF context.viewer # NIL THEN { IF Atom.GetPropFromList[ context.displayProps, $ViewerAdjusted ] # NIL THEN context.class.drawInViewer[context, NIL]; context.class.updateViewer[context]; context.pixelAspectRatio _ 1.0; context.stopMe^ _ FALSE; -- make sure stop button is released } ELSE context.pixels _ ImagerPixel.MakePixelMap[NIL]; -- this keeps other procs happy }; InterpressLoadBackground: ContextProc ~{ <> }; MakePage: ContextProc ~ { fileName: Rope.ROPE _ IF Atom.GetPropFromList[context.props, $OutputFile] # NIL THEN NARROW[Atom.GetPropFromList[context.props, $OutputFile]] ELSE "ThreeDImage.interpress"; ipRef: ImagerInterpress.Ref _ ImagerInterpress.Create[ G3dRender.PrependWorkingDirectory[ context, G3dRender.TackOnExtension[fileName, "interpress"] ] ]; scale: REAL _ 1.0 / (72.0 * 39.37); -- meters per pt. Action: PROC[imagerCtx: Imager.Context] ~ { rect: Rectangle; bkgrdClr: REF RGB _ NARROW[ Atom.GetPropFromList[context.props, $BackGround] ! ANY => SIGNAL G3dRender.Error[$MisMatch, "Interpress needs constant background"] ]; context.props _ Atom.PutPropOnList[context.props, $ImagerCtx, imagerCtx]; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[bkgrdClr^] ]; IF context.viewPort = NIL -- set default resolution THEN context.viewPort _ NEW[Imager.Rectangle _ [0, 0, 1024, 768]]; rect _ context.viewPort^; context.ndcToPixels _ [ -- render with origin at bottom left rect.w-1.0, rect.h-1.0, REAL[context.depthResolution-1], -- scaleX, scaleY, scaleZ rect.x, rect.y, 0.0 -- addX, addY, addZ ]; Imager.MaskRectangle[ imagerCtx, context.viewPort^ ]; G3dSortandDisplay.ShowShapes[ context ]; }; ImagerInterpress.DoPage[ipRef, Action, scale]; -- imager has to provide imagerCtx ImagerInterpress.Close[ipRef]; }; <> ClearViewPort: PUBLIC ContextProc ~ { context.class.drawInViewer[ context, NEW[ImagerProcRec _ [DoClear, NIL] ] ]; }; DoClear: ImagerProc ~ { clr: RGB; WITH Atom.GetPropFromList[context.props, $BackGround] SELECT FROM bkgrdClr: REF RGB => clr _ bkgrdClr^; -- constant color bkgrdImage: Context => -- background image SIGNAL G3dRender.Error[$MisMatch, "No background images with imager"]; ENDCASE => clr _ [ 0.0, 0.0, 0.0 ]; -- NIL, clear to black Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[clr] ]; Imager.MaskRectangle[ imagerCtx, context.viewPort^ ]; }; LineDesc: TYPE ~ RECORD[ p1, p2: Pair, color: Pixel]; Imager2DLine: PUBLIC PROC[ context: Context, p1, p2: Pair, color: Pixel] ~ { lineData: REF LineDesc _ NEW[ LineDesc _ [p1, p2, color] ]; IF context.class.displayType = $Interpress THEN DoLine[ context, NARROW[Atom.GetPropFromList[context.props, $ImagerCtx]], lineData ] ELSE context.class.drawInViewer[ context, NEW[ImagerProcRec _ [DoLine, lineData]] ]; }; DoLine: G3dRender.ImagerProc ~ { lineData: REF LineDesc _ NARROW[data]; color: Pixel _ lineData.color; p1: Pair _ PairToScreen[context, lineData.p1]; p2: Pair _ PairToScreen[context, lineData.p2]; Imager.SetStrokeWidth[ imagerCtx, 1.0 ]; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[[color[r]/255.0, color[g]/255.0, color[b]/255.0]] ]; Imager.MaskVector[ imagerCtx, p1, p2 ]; }; SetQuickLines: PUBLIC PROC[ imagerCtx: Imager.Context, color: Pixel] ~ { Imager.SetStrokeWidth[ imagerCtx, 1.0 ]; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[[color[r]/255.0, color[g]/255.0, color[b]/255.0]] ]; }; DoQuickLine: PUBLIC PROC[ imagerCtx: Imager.Context, p1, p2: Pair] ~ { Imager.MaskVector[ imagerCtx, p1, p2 ]; }; PolyDesc: TYPE ~ RECORD[ poly: PairSequence, color: Pixel]; Imager2DPoly: PUBLIC PROC[ context: Context, poly: PairSequence, color: Pixel] ~ { polyData: REF PolyDesc _ NEW[ PolyDesc _ [poly, color] ]; IF context.class.displayType = $Interpress THEN DoPoly[ context, NARROW[Atom.GetPropFromList[context.props, $ImagerCtx]], polyData ] ELSE context.class.drawInViewer[ context, NEW[ImagerProcRec _ [DoPoly, polyData]] ]; }; DoPoly: G3dRender.ImagerProc ~ { Path: Imager.PathProc ~ { moveTo[ PairToScreen[context, poly[poly.length-1]] ]; FOR i: NAT IN [0..poly.length) DO lineTo[ PairToScreen[context, poly[i]] ]; ENDLOOP; }; polyData: REF PolyDesc _ NARROW[data]; poly: PairSequence _ polyData.poly; color: Pixel _ polyData.color; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[[color[r]/255.0, color[g]/255.0, color[b]/255.0]] ]; Imager.MaskFill[imagerCtx, Path]; }; ImagerPolygon: PUBLIC PatchProc ~ { <> doProc: G3dRender.ImagerProc; WITH patch.renderData.shadingClass.renderMethod SELECT FROM style: REF RenderStyle => { renderStyle: RenderStyle _ style^; SELECT renderStyle FROM lines, shadedLines => doProc _ DoOutline; hiddenLines => doProc _ DoBoth; linesWnormals => doProc _ DoBothAndNormals; ENDCASE => doProc _ DoFill; }; ENDCASE => SIGNAL G3dRender.Error[$Unimplemented, "Only REF RenderStyle works here"]; IF context.class.displayType = $Interpress THEN doProc[context, NARROW[ Atom.GetPropFromList[context.props, $ImagerCtx]], patch] ELSE context.class.drawInViewer[ context, NEW[ImagerProcRec _ [doProc, patch]] ]; RETURN[NIL]; }; DoBoth: G3dRender.ImagerProc ~ { patch: REF Patch _ NARROW[data]; patch.ctlPt[0].shade.er _ patch.ctlPt[0].shade.eg _ patch.ctlPt[0].shade.eb _ 1.0; DoFill[ context, imagerCtx, data ]; patch.ctlPt[0].shade.er _ patch.ctlPt[0].shade.eg _ patch.ctlPt[0].shade.eb _ 0.0; DoOutline[ context, imagerCtx, data ]; }; DoBothAndNormals: G3dRender.ImagerProc ~ { patch: REF Patch _ NARROW[data]; IF patch.dir = back THEN DoNormals[ context, imagerCtx, data ]; patch.ctlPt[0].shade.er _ patch.ctlPt[0].shade.eg _ patch.ctlPt[0].shade.eb _ 1.0; DoFill[ context, imagerCtx, data ]; patch.ctlPt[0].shade.er _ patch.ctlPt[0].shade.eg _ patch.ctlPt[0].shade.eb _ 0.0; DoOutline[ context, imagerCtx, data ]; IF patch.dir # back THEN DoNormals[ context, imagerCtx, data ]; }; DoFill: G3dRender.ImagerProc ~ { Path: Imager.PathProc ~ { moveTo[[ patch.ctlPt[patch.nVtces-1].coord.sx, patch.ctlPt[patch.nVtces-1].coord.sy ]]; FOR i: NAT IN [0..patch.nVtces) DO lineTo[[ patch.ctlPt[i].coord.sx, patch.ctlPt[i].coord.sy ]]; ENDLOOP; }; patch: REF Patch _ NARROW[data]; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[ [ patch.ctlPt[0].shade.er, patch.ctlPt[0].shade.eg, patch.ctlPt[0].shade.eb ] ] ]; Imager.MaskFill[imagerCtx, Path]; }; DoOutline: G3dRender.ImagerProc ~ { Path: Imager.PathProc ~ { moveTo[[ patch.ctlPt[0].coord.sx, patch.ctlPt[0].coord.sy ]]; FOR i: NAT IN [1..patch.nVtces) DO lineTo[[ patch.ctlPt[i].coord.sx, patch.ctlPt[i].coord.sy ]]; ENDLOOP; }; patch: REF Patch _ NARROW[data]; Imager.SetStrokeWidth[ imagerCtx, 1.0 ]; Imager.SetStrokeJoint[ imagerCtx, round ]; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[ [ patch[0].shade.er, patch[0].shade.eg, patch[0].shade.eb ] ] ]; Imager.MaskStroke[context: imagerCtx, path: Path, closed: patch.type # $PolyLine]; }; DoNormals: G3dRender.ImagerProc ~ { Path: Imager.PathProc ~ { FOR i: NAT IN [0..patch.nVtces) DO ep2: Triple _ G3dClipXfmShade.XfmPtToDisplay[ context, G3dVector.Add[ [patch[i].coord.ex, patch[i].coord.ey, patch[i].coord.ez], [patch[i].shade.exn/2, patch[i].shade.eyn/2, patch[i].shade.ezn/2] ] ]; p2: IntegerPair _ [ Real.Round[ep2.x], Real.Round[ep2.y] ]; moveTo[[ patch[i].coord.sx, patch[i].coord.sy ]]; lineTo[ [p2.x, p2.y] ]; ENDLOOP; }; patch: REF Patch _ NARROW[data]; Imager.SetStrokeWidth[ imagerCtx, 1.0 ]; Imager.SetStrokeJoint[ imagerCtx, round ]; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[ [ 0.0, 0.0, 0.0 ] ] ]; Imager.MaskStroke[context: imagerCtx, path: Path, closed: patch.type # $PolyLine]; }; RopeDesc: TYPE ~ RECORD[rope: ROPE, position: Pair, color: Pixel, size: REAL, font: ROPE]; Draw2DRope: PUBLIC RopeProc ~ { <> ropeData: REF RopeDesc _ NEW[ RopeDesc _ [rope, position, color, size, font] ]; IF context.class.displayType = $Interpress THEN DoRope[ context: context, imagerCtx: NARROW[Atom.GetPropFromList[context.props, $ImagerCtx]], data: ropeData ] ELSE context.class.drawInViewer[ context, NEW[ImagerProcRec _ [DoRope, ropeData]] ]; }; DoRope: G3dRender.ImagerProc ~ { <> ropeData: REF RopeDesc _ NARROW[data]; color: Pixel _ ropeData.color; theFont: Imager.Font; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[[color[r]/255.0, color[g]/255.0, color[b]/255.0]] ]; IF ropeData.font = NIL THEN ropeData.font _ "Xerox/Pressfonts/TimesRoman-MRR"; theFont _ ImagerFont.Find[ropeData.font]; theFont _ ImagerFont.Scale[theFont, ropeData.size]; Imager.SetFont[imagerCtx, theFont]; Imager.SetXY[ imagerCtx, PairToScreen[context, ropeData.position] ]; Imager.ShowRope[imagerCtx, ropeData.rope]; }; <> RGBtoPixelValue: PROC[context: Context, clr: RGB] RETURNS[ value: Pixel ] ~ { value[r] _ Real.Round[255.0 * clr.R]; value[g] _ Real.Round[255.0 * clr.G]; value[b] _ Real.Round[255.0 * clr.B]; value[a] _ 0; value[z] _ 0; }; SetNamedColor: PROC [imagerCtx: Imager.Context, color: Rope.ROPE] ~ { clr: RGB _ ImagerColorFns.RGBFromHSL[ NamedColors.RopeToHSL[color] ]; Imager.SetColor[ imagerCtx, ImagerColor.ColorFromRGB[clr] ]; }; <> MakeInterpressPage: PUBLIC PROC[context: Context, fileName: ROPE] ~ { <> ipCtxt: Context _ G3dRender.Create[]; G3dRender.CopyContextData[ipCtxt, context]; ipCtxt.props _ Atom.PutPropOnList[ipCtxt.props, $OutputFile, fileName]; G3dRender.LoadDisplayClass[ipCtxt, $Interpress]; ipCtxt.viewer _ NIL; -- just in case ipCtxt.displayInValid _ TRUE; ipCtxt.class.render[ipCtxt]; -- should call MakePage }; Init[]; END.