DIRECTORY Atom, Real, Imager, ImagerBackdoor, ImagerPixel, G3dScanConvert, G3dBasic, G3dMatrix, G3dRenderWithImager, G3dClipXfmShade, G3dRender; QuickListProcs: CEDAR PROGRAM IMPORTS Atom, ImagerBackdoor, G3dMatrix, Real, G3dScanConvert, G3dRender, G3dRenderWithImager, G3dClipXfmShade ~ BEGIN PropList: TYPE ~ Atom.PropList; LORA: TYPE ~ LIST OF REF ANY; PixelMap: TYPE ~ ImagerPixel.PixelMap; Context: TYPE ~ G3dRender.Context; Pixel: TYPE ~ G3dRender.Pixel; Matrix: TYPE ~ G3dRender.Matrix; OutCode: TYPE ~ G3dRender.OutCode; NoneOut: OutCode ~ G3dRender.NoneOut; Patch: TYPE ~ G3dRender.Patch; PatchProc: TYPE ~ G3dRender.PatchProc; RenderData: TYPE ~ G3dRender.RenderData; ShapeClass: TYPE ~ G3dRender.ShapeClass; ShadingClass: TYPE ~ G3dRender.ShadingClass; Shape: TYPE ~ G3dRender.Shape; IntegerPairSequence: TYPE ~ G3dRender.IntegerPairSequence; IntegerPairSequenceRep: TYPE ~ G3dBasic.IntegerPairSequenceRep; Triple: TYPE ~ G3dRender.Triple; TripleSequence: TYPE ~ G3dRender.TripleSequence; TripleSequenceRep: TYPE ~ G3dBasic.TripleSequenceRep; TripleSeqSequence: TYPE ~ REF TripleSeqSequenceRep; TripleSeqSequenceRep: TYPE ~ RECORD[ length: NAT _ 0, s: SEQUENCE maxLength: CARDINAL OF TripleSequence ]; PatchSequence: TYPE ~ G3dRender.PatchSequence; BoolSequence: TYPE ~ REF BoolSequenceRep; BoolSequenceRep: TYPE ~ RECORD[ SEQUENCE length: CARDINAL OF BOOLEAN ]; BoolSeqSequence: TYPE ~ REF BoolSeqSequenceRep; BoolSeqSequenceRep: TYPE ~ RECORD[ SEQUENCE length: CARDINAL OF BoolSequence ]; Fix: PROC [REAL] RETURNS [INTEGER] ~ Real.InlineFixI; PutProp: PROC [propList: Atom.PropList, prop: REF ANY, val: REF ANY] RETURNS [Atom.PropList] ~ Atom.PutPropOnList; InitClasses: PROC[] ~ { -- register procedures for basic surface types polygonClass: ShapeClass _ G3dRender.GetShapeClass[$ConvexPolygon]; polygonClass.display _ DoDisplayList; G3dRender.RegisterShapeClass[polygonClass, polygonClass.type]; }; DoDisplayList: G3dRender.ShapeProc ~ { IF context.viewer # NIL -- do through viewer THEN context.class.drawInViewer[ context, NEW[G3dRender.ImagerProcRec _ [ViewerDisplayList, shape]] ] ELSE DrawShape[context, NIL, shape]; -- do directly RETURN[shape]; }; ViewerDisplayList: G3dRender.ImagerProc ~ { DoIt: PROC[pixelMap: PixelMap] ~ { shape: Shape _ NARROW[ data ]; tempPixels: PixelMap _ context.pixels; context.pixels _ pixelMap; DrawShape[context, imagerCtx, shape]; context.pixels _ tempPixels; }; ImagerBackdoor.AccessBufferRectangle[imagerCtx, DoIt, context.viewPort^]; }; DrawShape: PROC [ context: Context, imagerCtx: Imager.Context, shape: Shape ] ~ { imagerUsed: BOOLEAN _ FALSE; renderData: REF RenderData _ G3dRender.RenderDataFrom[shape]; dList: REF _ Atom.GetPropFromList[renderData.props, $LinesList]; shadingClass: REF ShadingClass _ G3dRender.ShadingClassFrom[shape]; shapeClass: REF ShapeClass _ G3dRender.ShapeClassFrom[shape]; color: Pixel _ [ Fix[shadingClass.color.R * 255.0], Fix[shadingClass.color.G * 255.0], Fix[shadingClass.color.B * 255.0], 0, 0 ]; SELECT context.class.displayType FROM $PseudoColor => color[r] _ 42 * (color[r] * 6 / 256) + 6 * (color[g] * 7 / 256) + (color[b] * 6 / 256) +2; $Gray => color[r] _ (color[r] + color[g] + color[b]) / 3; $Bitmap, $ImagerGray, $ImagerDithered, $ImagerFullClr, $Interpress => imagerUsed _ TRUE; ENDCASE; IF dList = NIL THEN dList _ MakeDisplayList[context, shape]; IF NOT shape.screenValid THEN [] _ shapeClass.validate[context, shape]; IF imagerUsed THEN G3dRenderWithImager.SetQuickLines[imagerCtx, color]; IF shapeClass.type = $ConvexPolygon THEN { list: IntegerPairSequence _ NARROW[dList]; FOR i: NAT IN [0..list.length) DO IF context.stopMe^ THEN RETURN; IF imagerUsed THEN G3dRenderWithImager.DoQuickLine[ imagerCtx, shape.vertices[list[i].x].screen, shape.vertices[list[i].y].screen ] ELSE G3dScanConvert.PutLine[ context, [ Fix[shape.vertices[list[i].x].screen.x], Fix[shape.vertices[list[i].x].screen.y] ], [ Fix[shape.vertices[list[i].y].screen.x], Fix[shape.vertices[list[i].y].screen.y] ], color, color ]; ENDLOOP; } ELSE { -- not polygonal have to transform curved paths list: TripleSeqSequence _ NARROW[dList]; xfm: Matrix _ G3dMatrix.Mul[shape.matrix, context.eyeSpaceXfm]; lsx, lsy: INTEGER; FOR i: NAT IN [0..list.length) DO FOR j: NAT IN [0..list[i].length) DO OPEN list[i][j]; clip: OutCode; ex, ey, ez, sx, sy: REAL; isx, isy: INTEGER; [[ex, ey, ez], clip] _ G3dClipXfmShade.XfmPtToEyeSpace[context, [x, y, z], xfm]; IF clip # NoneOut -- oops, G3dRender.XfmToEyeSpace got it wrong THEN { shape.clipState _ clipped; EXIT; } ELSE { sx _ context.eyeToNdc.scaleX * ex / ez + context.eyeToNdc.addX; sy _ context.eyeToNdc.scaleY * ey / ez + context.eyeToNdc.addY; isx _ Real.Fix[ context.ndcToPixels.scaleX * sx + context.ndcToPixels.addX ]; isy _ Real.Fix[ context.ndcToPixels.scaleY * sy + context.ndcToPixels.addY ]; IF j > 0 THEN G3dScanConvert.PutLine[context, [isx, isy], [lsx, lsy], color, color]; lsx _ isx; lsy _ isy; } ENDLOOP; ENDLOOP; }; }; MakeDisplayList: PROC [ context: Context, shape: Shape ] RETURNS[REF] ~ { IF G3dRender.ShapeClassFrom[shape].type = $ConvexPolygon THEN RETURN[ MakePolygonDisplayList[context, shape] ] ELSE RETURN[ MakePatchDisplayList[context, shape] ]; }; MakePolygonDisplayList: PROC [ context: Context, shape: Shape ] RETURNS[REF] ~ { renderData: REF RenderData _ G3dRender.RenderDataFrom[shape]; shapeClass: REF ShapeClass _ G3dRender.ShapeClassFrom[shape]; size: NAT _ shape.vertices.length; displayList: IntegerPairSequence _ NEW[IntegerPairSequenceRep[3*size]]; connections: BoolSeqSequence _ NEW[BoolSeqSequenceRep[shape.vertices.length]]; c1, c2, count: NAT _ 0; FOR i: NAT IN (0..shape.vertices.length) DO -- fill half matrix less diagonal with FALSE connections[i] _ NEW[ BoolSequenceRep[i] ]; FOR j: NAT IN [0..i) DO connections[i][j] _ FALSE; ENDLOOP; ENDLOOP; FOR i: NAT IN [0..shape.surfaces.length) DO IF shapeClass.type # $ConvexPolygon THEN SIGNAL G3dRender.Error[$MisMatch, "Operation only for convex polygons"] ELSE FOR j: NAT IN [0..shape.surfaces[i].vertices.length] DO k: NAT _ IF j = shape.surfaces[i].vertices.length THEN 0 ELSE j; c2 _ shape.surfaces[i].vertices[k]; IF j > 0 THEN { IF c1 > c2 THEN IF connections[c1][c2] = FALSE THEN { displayList[count] _ [c1, c2]; count _ count + 1; connections[c1][c2] _ TRUE; }; IF c2 > c1 THEN IF connections[c2][c1] = FALSE THEN { displayList[count] _ [c2, c1]; count _ count + 1; connections[c2][c1] _ TRUE; }; }; c1 _ c2; ENDLOOP; ENDLOOP; displayList.length _ count; renderData.props _ PutProp[renderData.props, $LinesList, displayList]; RETURN[displayList]; }; tol: REAL _ .001; -- tolerance for endpoint matching GrabEdges: PatchProc ~ { displayList: TripleSeqSequence _ NARROW[ Atom.GetPropFromList[patch.renderData.props, $LinesList] ]; FOR i: NAT IN [0..displayList.length) DO OPEN patch[patch.nVtces-1].coord; pt: Triple _ displayList[i][0]; -- get first point in sequence IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN { OPEN patch[0].coord; -- opposite endpoints match, try other ends pt: Triple _ displayList[i][displayList[i].length-1]; -- get last point in sequence IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN { OPEN patch[patch.nVtces/2].coord; -- check middle points pt: Triple _ displayList[i][displayList[i].length - 1 - patch.nVtces/2]; IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN RETURN[patch]; -- both ends and middle match, line stored in other direction }; }; pt _ displayList[i][displayList[i].length-1]; IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN { OPEN patch[0].coord; -- last endpoints match, try other end pt: Triple _ displayList[i][0]; -- get first point in sequence IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN { OPEN patch[patch.nVtces/2].coord; -- check middle points pt: Triple _ displayList[i][patch.nVtces/2]; IF ABS[pt.x - x] < tol AND ABS[pt.y - y] < tol AND ABS[pt.z - z] < tol THEN RETURN[patch]; -- both ends and middle match, line stored in other direction }; }; ENDLOOP; IF displayList.length = displayList.maxLength THEN { -- extend display list newList: TripleSeqSequence _ NEW[ TripleSeqSequenceRep[displayList.length + displayList.length / 2] ]; FOR i: NAT IN [0..displayList.length) DO newList[i] _ displayList[i] ENDLOOP; newList.length _ displayList.length; displayList _ newList; }; displayList[displayList.length] _ NEW[TripleSequenceRep[patch.nVtces]]; -- add new edge FOR i: NAT IN [0..patch.nVtces) DO displayList[displayList.length][i] _ [ patch[i].coord.x, patch[i].coord.y, patch[i].coord.z ]; ENDLOOP; displayList[displayList.length].length _ patch.nVtces; displayList.length _ displayList.length + 1; RETURN[patch]; }; MakePatchDisplayList: PROC [ context: Context, shape: Shape ] RETURNS[REF] ~ { renderData: REF RenderData _ G3dRender.RenderDataFrom[shape]; size: NAT _ shape.vertices.length; displayList: TripleSeqSequence _ NEW[TripleSeqSequenceRep[3*size]]; -- max. for triangles tempProc: PatchProc _ context.class.displayPolygon; context.class.displayPolygon _ GrabEdges; -- ambush polygon display proc renderData.props _ PutProp[renderData.props, $LinesList, displayList]; FOR i: NAT IN [0..renderData.patch.length) DO IF renderData.patch[i] # NIL THEN [] _ renderData.class.displayPatch[ context, renderData.patch[i] ]; ENDLOOP; context.class.displayPolygon _ tempProc; -- restore polygon display proc RETURN[displayList]; }; InitClasses[]; END. ΌQuickListProcs.mesa Copyright Σ 1987 by Xerox Corporation. All rights reserved. Frank Crow, July 7, 1989 7:15:46 pm PDT Quick display lists for lines. Bloomenthal, September 26, 1988 12:04:42 pm PDT Type Definitions Renamed Procedures Initialization of Classes Line Drawings PROC[context: Context, shape: Shape, data: REF ANY _ NIL] RETURNS[Shape] Call this to get through viewer to draw on screen PROC[context: Context, imagerCtx: Imager.Context, data: REF ANY _ NIL] This gets pixel map and calls proc which draws lines based on display list This acquires display list from shape.props and executes it, calls proc to build list if none Creates display list for line drawings of polygonal object, culls duplicated edges Allocate display list; Allow room for triangular mesh ( < 3 edges per vertex ) PROC[context: Context, patch: REF Patch, data: REF ANY _ NIL] RETURNS[REF Patch] Used to temporarily replace polygon rendering proc in context, captures calls and culls duplicates, stores result in display list Creates display list for line drawings of patch shape by replacing polygon display proc with GrabEdges then calling for display of all patches of shape to capture the resulting polygon calls Κ ˜Ihead2™™˜>J˜——™ šž œ˜&Nšœ'œœœ™:Nšœ™M™1šœœŸ˜:šœ˜ Mšœ œ6˜BM˜—Nšœœ Ÿ˜4—Nšœ˜N˜J˜N™—šžœ˜+Nšœ4œœœ™FN™Jšžœœ˜#Jšœœ ˜J˜DJ˜%J˜J˜—J˜IN˜—šž œœB˜QN™]Jšœ œœ˜Jšœ œ.˜=Nšœœ6˜@Jšœœ2˜CJšœ œ.˜=šœ˜Jšœ#˜#Jšœ#˜#Jšœ#˜#J˜J˜—šœ˜%˜N˜[—N˜9šœF˜FNšœ œ˜—Nšœ˜—Jšœ œœ)˜