<> <> <> <> <> <<>> DIRECTORY Atom USING [ GetPropFromList, PutPropOnList ], Real USING [ Fix ], ImagerBackdoor USING [ AccessBufferRectangle ], ImagerPixel USING [ PixelMap ], ScanConvert USING [ PutLine ], G3dMatrix USING [ Mul ], ShapeUtilities USING [ ShapePatch, ShapePatchToPatch, XfmPtToEyeSpace ], ThreeDBasics USING [ Context, Error, GetSurfaceType, ImagerProc, ImagerProcRec, IntegerPairSequence, NoneOut, OutCode, Patch, PatchProc, Pixel, PtrPatchSequence, RegisterSurfaceType, ShapeClass, ShapeInstance, ShapeProc, Triple, TripleSequence, Xfm3D ]; QuickListProcs: CEDAR PROGRAM IMPORTS Atom, ImagerBackdoor, G3dMatrix, Real, ScanConvert, ShapeUtilities, ThreeDBasics ~ BEGIN <> LORA: TYPE ~ LIST OF REF ANY; PixelMap: TYPE ~ ImagerPixel.PixelMap; Context: TYPE ~ ThreeDBasics.Context; Pixel: TYPE ~ ThreeDBasics.Pixel; Xfm3D: TYPE ~ ThreeDBasics.Xfm3D; OutCode: TYPE ~ ThreeDBasics.OutCode; NoneOut: OutCode ~ ThreeDBasics.NoneOut; ShapePatch: TYPE ~ ShapeUtilities.ShapePatch; Patch: TYPE ~ ThreeDBasics.Patch; PatchProc: TYPE ~ ThreeDBasics.PatchProc; ShapeClass: TYPE ~ ThreeDBasics.ShapeClass; ShapeInstance: TYPE ~ ThreeDBasics.ShapeInstance; IntegerPairSequence: TYPE ~ ThreeDBasics.IntegerPairSequence; Triple: TYPE ~ ThreeDBasics.Triple; TripleSequence: TYPE ~ ThreeDBasics.TripleSequence; TripleSeqSequence: TYPE ~ RECORD[ length: NAT _ 0, s: SEQUENCE maxLength: CARDINAL OF REF TripleSequence ]; PtrPatchSequence: TYPE ~ ThreeDBasics.PtrPatchSequence; BoolSequence: TYPE ~ RECORD[ SEQUENCE length: CARDINAL OF BOOLEAN ]; BoolSeqSequence: TYPE ~ RECORD[ SEQUENCE length: CARDINAL OF REF BoolSequence ]; <> InitClasses: PROC[] ~ { -- register procedures for basic surface types polygonClass: ShapeClass _ ThreeDBasics.GetSurfaceType[$ConvexPolygon]; polygonClass.display _ DoDisplayList; ThreeDBasics.RegisterSurfaceType[polygonClass, polygonClass.type]; }; <> DoDisplayList: ThreeDBasics.ShapeProc ~ { <> <> <> IF context.viewer # NIL -- do through viewer THEN context.class.drawInViewer[ context, NEW[ThreeDBasics.ImagerProcRec _ [ViewerDisplayList, shape]] ] ELSE DrawShape[context, shape]; -- do directly RETURN[shape]; }; <<>> ViewerDisplayList: ThreeDBasics.ImagerProc ~ { <> <> DoIt: PROC[pixelMap: PixelMap] ~ { shape: REF ShapeInstance _ NARROW[ data ]; tempPixels: PixelMap _ context.pixels; context.pixels _ pixelMap; DrawShape[context, shape]; context.pixels _ tempPixels; }; ImagerBackdoor.AccessBufferRectangle[imagerCtx, DoIt, context.viewPort^]; }; DrawShape: PROC [ context: REF Context, shape: REF ShapeInstance ] ~ { <> dList: REF _ Atom.GetPropFromList[shape.props, $LinesList]; color: Pixel _ [ Real.Fix[shape.shadingClass.color.R * 255.0], Real.Fix[shape.shadingClass.color.G * 255.0], Real.Fix[shape.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; ENDCASE; IF dList = NIL THEN dList _ MakeDisplayList[context, shape]; IF shape.class.type = $ConvexPolygon THEN { list: REF IntegerPairSequence _ NARROW[dList]; FOR i: NAT IN [0..list.length) DO IF context.stopMe^ THEN RETURN; ScanConvert.PutLine[ context, [ Real.Fix[shape.vertex[list[i].x].sx], Real.Fix[shape.vertex[list[i].x].sy] ], [ Real.Fix[shape.vertex[list[i].y].sx], Real.Fix[shape.vertex[list[i].y].sy] ], color, color ]; ENDLOOP; } ELSE { -- not polygonal have to transform curved paths list: REF TripleSeqSequence _ NARROW[dList]; xfm: Xfm3D _ G3dMatrix.Mul[shape.position, 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 ] _ ShapeUtilities.XfmPtToEyeSpace[ context, [x, y, z], xfm ]; IF clip # NoneOut -- oops, ShapeUtilities.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 ScanConvert.PutLine[context, [isx, isy], [lsx, lsy], color, color]; lsx _ isx; lsy _ isy; } ENDLOOP; ENDLOOP; }; }; MakeDisplayList: PROC [ context: REF Context, shape: REF ShapeInstance ] RETURNS[REF] ~ { IF shape.class.type = $ConvexPolygon THEN RETURN[ MakePolygonDisplayList[context, shape] ] ELSE RETURN[ MakePatchDisplayList[context, shape] ]; }; MakePolygonDisplayList: PROC [ context: REF Context, shape: REF ShapeInstance ] RETURNS[REF] ~ { <> patches: REF PtrPatchSequence; size: NAT _ shape.vertex.length; displayList: REF IntegerPairSequence _ NEW[IntegerPairSequence[3*size]]; -- all triangles makes < 3 edges per vertex connections: REF BoolSeqSequence _ NEW[BoolSeqSequence[shape.vertex.length]]; c1, c2, count: NAT _ 0; patches _ NARROW[shape.surface, REF PtrPatchSequence]; FOR i: NAT IN (0..shape.vertex.length) DO -- fill half matrix less diagonal with FALSE connections[i] _ NEW[ BoolSequence[i] ]; FOR j: NAT IN [0..i) DO connections[i][j] _ FALSE; ENDLOOP; ENDLOOP; FOR i: NAT IN [0..shape.numSurfaces) DO IF shape.class.type # $ConvexPolygon THEN SIGNAL ThreeDBasics.Error[[$MisMatch, "Operation only for convex polygons"]] ELSE FOR j: NAT IN [0..patches[i].nVtces] DO k: NAT _ IF j = patches[i].nVtces THEN 0 ELSE j; c2 _ patches[i].vtxPtr[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; shape.props _ Atom.PutPropOnList[shape.props, $LinesList, displayList]; RETURN[displayList]; }; tol: REAL _ .001; -- tolerance for endpoint matching GrabEdges: PatchProc ~ { <> <> shape: REF ShapeInstance _ NARROW[ Atom.GetPropFromList[patch.props, $Shape] ]; displayList: REF TripleSeqSequence _ NARROW[ Atom.GetPropFromList[shape.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: REF TripleSeqSequence _ NEW[ TripleSeqSequence[displayList.length + shape.vertex.length] ]; FOR i: NAT IN [0..displayList.length) DO newList[i] _ displayList[i] ENDLOOP; newList.length _ displayList.length; displayList _ newList; }; displayList[displayList.length] _ NEW[TripleSequence[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: REF Context, shape: REF ShapeInstance ] RETURNS[REF] ~ { <> patches: REF PtrPatchSequence; size: NAT _ shape.vertex.length; displayList: REF TripleSeqSequence _ NEW[TripleSeqSequence[3*size]]; -- max. for triangles tempProc: PatchProc _ context.class.displayPolygon; context.class.displayPolygon _ GrabEdges; -- ambush polygon display proc shape.props _ Atom.PutPropOnList[shape.props, $LinesList, displayList]; patches _ NARROW[shape.surface, REF PtrPatchSequence]; FOR i: NAT IN [0..shape.numSurfaces) DO IF patches[i] # NIL THEN { patch: REF Patch _ ShapeUtilities.ShapePatchToPatch[ context, NEW[ ShapePatch _ [shape, i, 0, 0, 0.0] ] ]; [] _ shape.class.displayPatch[ context, patch ]; }; ENDLOOP; context.class.displayPolygon _ tempProc; -- restore polygon display proc RETURN[displayList]; }; InitClasses[]; END.