<> <> <> <> <> <<>> 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.