DIRECTORY Atom, Basics, G3dBasic, G3dMatrix, G3dRender, G3dScanConvert, G3dClipXfmShade, G3dShape, G3dVector; PolySilhouetteProcs: CEDAR MONITOR IMPORTS Atom, Basics, G3dMatrix, G3dRender, G3dClipXfmShade, G3dVector = BEGIN Ray: TYPE ~ G3dBasic.Ray; NatSequence: TYPE ~ G3dRender.NatSequence; NatSequenceRep: TYPE ~ G3dBasic.NatSequenceRep; Pair: TYPE ~ G3dRender.Pair; Triple: TYPE ~ G3dRender.Triple; TripleSequence: TYPE ~ G3dRender.TripleSequence; TripleSequenceRep: TYPE ~ G3dBasic.TripleSequenceRep; RGB: TYPE ~ G3dRender.RGB; RealSequence: TYPE ~ G3dRender.RealSequence; RealSequenceRep: TYPE ~ G3dBasic.RealSequenceRep; Context: TYPE ~ G3dRender.Context; SixSides: TYPE ~ G3dRender.SixSides; Matrix: TYPE ~ G3dRender.Matrix; Shape: TYPE ~ G3dRender.Shape; Vertex: TYPE ~ G3dShape.Vertex; Patch: TYPE ~ G3dRender.Patch; PatchSequence: TYPE ~ G3dRender.PatchSequence; PatchSequenceRep: TYPE ~ G3dRender.PatchSequenceRep; FaceRep: TYPE ~ G3dShape.FaceRep; FaceSequenceRep: TYPE ~ G3dShape.FaceSequenceRep; PatchProc: TYPE ~ G3dRender.PatchProc; CtlPoint: TYPE ~ G3dRender.CtlPoint; CtlPtInfo: TYPE ~ G3dRender.CtlPtInfo; CtlPtInfoSequence: TYPE ~ G3dRender.CtlPtInfoSequence; CtlPtInfoProc: TYPE ~ G3dRender.CtlPtInfoProc; Shading: TYPE ~ G3dRender.Shading; ShadingClass: TYPE ~ G3dRender.ShadingClass; RenderStyle: TYPE ~ G3dRender.RenderStyle; RenderData: TYPE ~ G3dRender.RenderData; ShapeClass: TYPE ~ G3dRender.ShapeClass; ShapeProc: TYPE ~ G3dRender.ShapeProc; ClipState: TYPE ~ G3dRender.ClipState; OutCode: TYPE ~ G3dRender.OutCode; AllOut: OutCode ~ G3dRender.AllOut; NoneOut: OutCode ~ G3dRender.NoneOut; FacingDir: TYPE ~ G3dRender.FacingDir; LORA: TYPE = LIST OF REF ANY; MidPtProc: TYPE ~ PROC[v0, v1: REF CtlPtInfo] RETURNS[REF CtlPtInfo]; nullTriple: Triple ~ [0.0, 0.0, 0.0]; Corner: TYPE ~ RECORD [ inVtx, outVtx: NAT _ 0, inDir, outDir, normal, interiorKnot: Triple _ nullTriple, concave: BOOLEAN _ FALSE ]; CornerSeq: TYPE ~ RECORD [ length: NAT _ 0, s: SEQUENCE maxLength: NAT OF Corner ]; CornerSeqSeq: TYPE ~ RECORD [ length: NAT _ 0, s: SEQUENCE maxLength: NAT OF REF CornerSeq ]; TangentSet: TYPE ~ RECORD [t0, et0, t1, et1: Triple _ nullTriple]; TangentSeq: TYPE ~ RECORD [length: NAT _ 0, s: SEQUENCE maxLength: NAT OF TangentSet]; TangentTriple: TYPE ~ ARRAY [0..3) OF TangentSet; TangentQuad: TYPE ~ ARRAY [0..4) OF TangentSet; TangentSeqSeq: TYPE ~ RECORD [ length: NAT _ 0, s: SEQUENCE maxLength: NAT OF REF TangentSeq]; Triangle: TYPE ~ RECORD [ v: ARRAY[0..3) OF CtlPtInfo, t: ARRAY[0..3) OF TangentSet ]; NatSequenceSequence: TYPE ~ RECORD [ length: NAT _ 0, s: SEQUENCE maxLength: NAT OF NatSequence ]; BoolSequence: TYPE ~ RECORD [length: NAT _ 0, s: SEQUENCE maxLength: NAT OF BOOLEAN]; Add: PROC[v1, v2: Triple] RETURNS[Triple] ~ G3dVector.Add; Mul: PROC[v: Triple, s: REAL] RETURNS[Triple] ~ G3dVector.Mul; Cross: PROC[v1, v2: Triple] RETURNS[Triple] ~ G3dVector.Cross; Div: PROC[v: Triple, s: REAL] RETURNS[Triple] ~ G3dVector.Div; Dot: PROC[v1, v2: Triple] RETURNS[REAL] ~ G3dVector.Dot; Length: PROC[v: Triple] RETURNS[REAL] ~ G3dVector.Length; Negate: PROC[v: Triple] RETURNS[Triple] ~ G3dVector.Negate; Nmlize: PROC[v: Triple] RETURNS[Triple] ~ G3dVector.Normalize; Sub3: PROC[v1, v2: Triple] RETURNS[Triple] ~ G3dVector.Sub; ReleasePatch: PROC [p: REF Patch] ~ G3dClipXfmShade.ReleasePatch; GetPatch: PROC [size: NAT] RETURNS [REF Patch] ~ G3dClipXfmShade.GetPatch; GetProp: PROC [propList: Atom.PropList, prop: REF ANY] RETURNS [REF ANY] ~ Atom.GetPropFromList; PutProp: PROC [propList: Atom.PropList, prop: REF ANY, val: REF ANY] RETURNS [Atom.PropList] ~ Atom.PutPropOnList; Sqr: PROCEDURE [number: REAL] RETURNS [REAL] ~ INLINE { RETURN[number * number]; }; DisplayNothing: PatchProc ~ { -- dummy routine for timing tests RETURN[ patch ]; }; DisplayPatchSilhouette: PatchProc ~ { shape: Shape _ NARROW[ GetProp[patch.props, $Shape] ]; patchNo: NAT _ NARROW[ GetProp[patch.props, $PatchNo], REF NAT ]^; renderData: REF RenderData _ patch.renderData; RETURN[patch]; }; InitClasses: PROC[] ~ { -- register procedures for basic surface types standardClass: ShapeClass _ G3dRender.GetShapeClass[$ConvexPolygon]; standardClass.type _ $PolygonWithSilhouette; standardClass.validate _ ValidatePolyWSilhouette; standardClass.displayPatch _ DisplayPatchSilhouette; G3dRender.RegisterShapeClass[standardClass, $PolygonWithSilhouette]; }; ValidatePolyWSilhouette: ShapeProc ~ { ValidateScreenCoords: PROC[] ~ { FOR i: NAT IN [0..shape.vertices.length) DO eVtx: Triple _ G3dMatrix.Transform[ shape.vertices[i].point, xfm]; eVtx _ G3dClipXfmShade.XfmPtToDisplay[ context, eVtx ]; shape.vertices[i].screen.x _ eVtx.x; shape.vertices[i].screen.y _ eVtx.y; ENDLOOP; shape.screenValid _ TRUE; }; render: REF RenderData _ G3dRender.RenderDataFrom[shape]; shapeClass: REF ShapeClass _ render.class; shadingClass: REF ShadingClass _ render.shadingClass; renderStyle: RenderStyle; xfm: Matrix _ G3dMatrix.Mul[shape.matrix, context.eyeSpaceXfm]; allPolysIn, allPolysOut: BOOLEAN _ TRUE; WITH shadingClass.renderMethod SELECT FROM style: REF RenderStyle => renderStyle _ style^; ENDCASE => renderStyle _ smooth; -- default to smooth to get normals and shading IF renderStyle # faceted THEN { -- get vertex normals IF NOT shape.vertices.valid.normal THEN G3dClipXfmShade.GetVtxNmls[context, shape]; } ELSE { -- get face normals IF shape.faces = NIL THEN { shape.faces _ NEW[FaceSequenceRep[shape.surfaces.length]]; shape.faces.length _ shape.surfaces.length; FOR i: NAT IN [0..shape.faces.length) DO shape.faces[i] _ NEW[FaceRep]; ENDLOOP; }; IF NOT shape.faces.valid.normal THEN G3dClipXfmShade.GetPolyNmls[context, shape]; }; IF GetProp[render.props, $Hidden] # NIL THEN RETURN[shape]; -- don't bother, not visible IF NOT render.patchesValid OR context.changed OR render.patch = NIL THEN { IF render.patch = NIL THEN { render.patch _ NEW[PatchSequenceRep[shape.surfaces.length]]; render.patch.length _ shape.surfaces.length; FOR i: NAT IN [0..render.patch.length) DO render.patch[i] _ NEW[Patch[shape.surfaces[i].length]]; FOR j: NAT IN [0..shape.surfaces[i].length) DO vtx: NAT _ shape.surfaces[i][j]; render.patch[i][j].coord.x _ shape.vertices[vtx].point.x; render.patch[i][j].coord.y _ shape.vertices[vtx].point.y; render.patch[i][j].coord.z _ shape.vertices[vtx].point.z; render.patch[i][j].shade.xn _ shape.vertices[vtx].normal.x; render.patch[i][j].shade.yn _ shape.vertices[vtx].normal.y; render.patch[i][j].shade.zn _ shape.vertices[vtx].normal.z; render.patch[i][j].shade.txtrX _ shape.vertices[vtx].texture.x; render.patch[i][j].shade.txtrY _ shape.vertices[vtx].texture.y; render.patch[i][j].vtxPtr _ vtx; ENDLOOP; render.patch[i].nVtces _ shape.surfaces[i].length; render.patch[i].type _ shape.type; render.patch[i].oneSided _ NOT shape.showBackfaces; render.patch[i].renderData _ render; -- store REF to shading information render.patch[i].props _ PutProp[render.patch[i].props, $Shape, shape]; render.patch[i].props _ PutProp[render.patch[i].props, $PatchNo, NEW[NAT _ i]]; ENDLOOP; }; IF renderStyle = lines AND shape.clipState = in AND render.class.display # NIL THEN { ValidateScreenCoords[]; RETURN [ shape ]; }; shape.screenExtent _ [[32768, 32768], [0, 0]]; -- initialize for computing screenExtent FOR i: NAT IN [0..render.patch.length) DO andOfCodes: OutCode _ AllOut; -- test for trivially out orOfCodes: OutCode _ NoneOut; -- test for trivially in FOR j: NAT IN [0..render.patch[i].nVtces) DO OPEN render.patch[i][j].coord; -- transform control points to eyespace [ [ex, ey, ez] ] _ G3dMatrix.Transform[ [x, y, z] , xfm]; IF shape.clipState = clipped THEN { clip _ G3dClipXfmShade.GetClipCodeForPt[ context, [ex, ey, ez] ]; orOfCodes _ LOOPHOLE[ Basics.BITOR[LOOPHOLE[orOfCodes], LOOPHOLE[ clip] ], OutCode]; andOfCodes _ LOOPHOLE[ Basics.BITAND[ LOOPHOLE[andOfCodes], LOOPHOLE[ clip] ], OutCode]; } ELSE clip _ NoneOut; IF renderStyle = smooth OR renderStyle = shadedLines THEN { OPEN render.patch[i][j].shade; tmpShininess: REAL; vtx: NAT _ render.patch[i][j].vtxPtr; [xn, yn, zn] _ shape.vertices[vtx].normal; [r, g, b] _ shape.vertices[vtx].color; t _ shape.vertices[vtx].transmittance; IF shape.faces # NIL THEN IF shape.faces.valid.color THEN { -- scale by face color clr: Triple _ shape.faces[i].color; r _ clr.x * r; g _ clr.y * g; b _ clr.z * b; }; [[exn, eyn, ezn]] _ G3dMatrix.TransformVec[ [xn, yn, zn] , xfm]; tmpShininess _ shadingClass.shininess; shadingClass.shininess _ 0.0; render.patch[i][j] _ shadingClass.shadeVtx[ context, render.patch[i][j], shadingClass ]; shadingClass.shininess _ tmpShininess; }; IF renderStyle = lines THEN { OPEN render.patch[i][j].shade; [er, eg, eb] _ shadingClass.color; }; ENDLOOP; IF orOfCodes = NoneOut THEN render.patch[i].clipState _ in -- default case ELSE IF andOfCodes # NoneOut THEN render.patch[i].clipState _ out ELSE render.patch[i].clipState _ clipped; IF shape.clipState = clipped THEN { allPolysIn _ allPolysIn AND (render.patch[i].clipState = in); allPolysOut _ allPolysOut AND (render.patch[i].clipState = out); }; IF renderStyle = faceted THEN { OPEN render.patch[i][0].shade; [xn, yn, zn] _ shape.faces[i].normal; [r, g, b] _ shape.faces[i].color; t _ shape.faces[i].transmittance; [[exn, eyn, ezn]] _ G3dMatrix.TransformVec[ shape.faces[i].normal, xfm]; render.patch[i][0] _ shadingClass.shadeVtx[context, render.patch[i][0], shadingClass]; FOR j: NAT IN [1..render.patch[i].nVtces) DO render.patch[i][j].shade.exn _ render.patch[i][0].shade.exn; render.patch[i][j].shade.eyn _ render.patch[i][0].shade.eyn; render.patch[i][j].shade.ezn _ render.patch[i][0].shade.ezn; render.patch[i][j].shade.er _ render.patch[i][0].shade.er; render.patch[i][j].shade.eg _ render.patch[i][0].shade.eg; render.patch[i][j].shade.eb _ render.patch[i][0].shade.eb; ENDLOOP; }; IF render.patch[i].clipState # out THEN FOR j: NAT IN [0..render.patch[i].nVtces) DO OPEN render.patch[i][j].coord; -- xfm to display, update shape screen extent [ [sx, sy, sz] ] _ G3dClipXfmShade.XfmPtToDisplay[ context, [ex, ey, ez], shape ]; ENDLOOP; ENDLOOP; IF shape.clipState = clipped THEN -- refine shape clipstate based on polygon states IF allPolysIn THEN shape.clipState _ in ELSE IF allPolysOut THEN shape.clipState _ out; render.patchesValid _ TRUE; IF shape.clipState = in AND renderStyle = lines AND render.class.display # NIL THEN ValidateScreenCoords[]; -- prepare for unclipped line drawings }; RETURN[shape]; }; InitClasses[]; END. ΪPolySilhouetteProcs.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last Edited by: Crow, May 30, 1989 11:37:40 am PDT Bloomenthal, September 14, 1988 1:06:44 pm PDT Types RECORD[coord: CtlPoint, shade: Shading, vtxPtr: NAT, data: REF]; Represents a corner of a polygon, - inVtx is the vertex at the other end of the incoming edge (previous vertex in order), - outVtx is other vertex on outgoing edge, - inDir, outDir are the corresponding outward direction vectors, - normal is the carefully determined normal vector - concave = TRUE indicates corner is concave vertex needing reversed cross product. Represents the tangents at the endpoints of an edge (in object space and eyespace), the edge is ordered in the vertex order of the polygon (t0 at leading endpoint, t1 at trailing endpoint) Renamed Procedures Global Variables -- showLines: BOOLEAN; -- debug and pedagogical aid Utility Procedures Display Procedures PROC[ context: Context, patch: REF Patch, data: REF ANY _ NIL ] RETURNS[REF Patch] Initialization of Classes Validation Procedure PROC[context: Context, shape: Shape, data: REF] RETURNS[Shape]; Update patch structure under renderData to ready everything for display, etc. Shape class, shading class, matrix, bounding Sphere, and gross clip state are expected valid Get vertex, face normals if not yet present Create or update patch-by-patch description Build patch sequence for shape Store REF to parent shape and polygon number in object Patches built, update shading, transformed vertices, clip state Catch unclipped line drawings and expedite Transform and shade vertices, get clip state for each polygon If vertex normals used for shading, transform and get shading Cache shininess to get vertex shades without highlights Plain lines take object color Collect clipping data for vertices to tag patches, patches to tag shapes Update polygons for faceted shading Get screen coordinates for on-screen polygons Refine shape clipstate based on polygon state Κ Κ˜Ihead™šœ Οmœ1™Jš œžœžœ˜>Jš œžœžœžœ˜>Jš œžœžœžœ˜8Jš œžœ žœžœ˜9Jš œžœ žœ˜;Jš œžœ žœ˜>Jš œžœžœ˜;Jš  œžœžœ'˜AJš  œžœžœžœžœ#˜JJš œžœ!žœžœžœžœžœ.˜uJš œžœ!žœžœžœžœž œ&˜x—™Nšœžœ Οc™;—™defaultš œž œ žœžœžœžœžœ˜SO˜——™š œ‘!˜DNšžœ ˜N˜—š œ˜%Nšžœžœžœžœžœžœžœ™RJšœžœ!˜6Jš œ žœžœ"žœžœ˜BJšœ žœ˜.Jšžœ˜J˜J˜——™š  œžœ ‘.˜IOšœD˜DO˜J˜,J˜1J˜4JšœE˜EJ˜——™šŸœ˜&Jšžœ'žœžœ™?O™MJ™\š œžœ˜ šžœžœžœž˜+JšœB˜BJšœ7˜7JšœL˜LJšžœ˜—Jšœžœ˜J˜—Jšœžœ.˜9Jšœ žœ˜*Jšœžœ$˜5Jšœ˜Jšœ?˜?Jšœžœžœ˜(J˜šžœžœž˜*Jšœžœ%˜/Jšžœ‘/˜R—˜JšŸ+™+—šžœ˜šžœ ‘˜#Jšžœžœ‘žœ0˜W—šžœ‘˜šžœžœžœ˜Jšœžœ)˜:Jšœ+˜+Jš žœžœžœžœžœ žœ˜PJšœ˜—Jšžœžœžœ-˜QJ˜——˜JšŸ+™+—Jš žœ"žœžœžœ ‘˜Xš žœžœžœžœžœžœ˜Jšžœžœžœ˜JšŸ™Jšœžœ*˜