G3dRenderWithImagerImpl.mesa
Last Edited by: Crow, September 21, 1989 1:52:37 pm PDT
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
Types
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;
Initialize Standard Displays
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 ~{
No backgrounds with Interpress output. It is assumed that backgrounds can be added with other tools more efficiently
};
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];
};
Low-level drawing
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 ~ {
PROC[ context: Context, patch: REF Patch, data: REF ANY ← NIL ] RETURNS[REF Patch]
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 ~ {
Put a string of characters on the screen
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 ~ {
PROC[ context: Context, imagerCtx: Imager.Context, data: REF ANY ]
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];
};