DIRECTORY Atom USING [ DottedPair, DottedPairNode, GetPropFromList, PropList, PutPropOnList, RemPropFromList ], Basics USING [ BITOR, BITAND, BITSHIFT ], Real USING [ Float ], RealFns USING [ SqRt, AlmostEqual ], G3dVector USING [ Add, Cross, NearestToLine, Normalize, Null ], G3dBasic USING [ origin, Ray ], ScanConvert USING [ justNoticeable ], ThreeDBasics USING [ AllOut, ClipState, Context, Error, FacingDir, GetSurfaceType, NoneOut, OutCode, Pair, Patch, PatchProc, PatchSequence, PtrPatch, PtrPatchSequence, RealSequence, RegisterSurfaceType, RGB, ShadingSequence, ShadingClass, ShadingValue, ShapeClass, ShapeInstance, ShapeProc, SixSides, Triple, Vertex, VertexInfo, VertexInfoProc, VertexInfoSequence, VertexSequence, Xfm3D ], ShapeUtilities USING [ BackFacing, GetClipCodeForPt, GetPatch, GetPatchClipState, GetVertexInfo, ReleasePatch, ReleaseVertexInfo, ShadePoly, XfmPtToDisplay, XfmToEyeSpace ], SurfaceRender USING [ GetPtrPatchClipState, OutputPolygon, ValidatePolyhedron ]; StandardPatchProcs: CEDAR MONITOR IMPORTS Atom, Basics, G3dVector, Real, RealFns, SurfaceRender, ThreeDBasics, ShapeUtilities = BEGIN Ray: TYPE ~ G3dBasic.Ray; RGB: TYPE ~ ThreeDBasics.RGB; RealSequence: TYPE ~ ThreeDBasics.RealSequence; Context: TYPE ~ ThreeDBasics.Context; SixSides: TYPE ~ ThreeDBasics.SixSides; Pair: TYPE ~ ThreeDBasics.Pair; Triple: TYPE ~ ThreeDBasics.Triple; Xfm3D: TYPE ~ ThreeDBasics.Xfm3D; ShapeInstance: TYPE ~ ThreeDBasics.ShapeInstance; Patch: TYPE ~ ThreeDBasics.Patch; PatchSequence: TYPE ~ ThreeDBasics.PatchSequence; PatchProc: TYPE ~ ThreeDBasics.PatchProc; PtrPatch: TYPE ~ ThreeDBasics.PtrPatch; PtrPatchSequence: TYPE ~ ThreeDBasics.PtrPatchSequence; Vertex: TYPE ~ ThreeDBasics.Vertex; VertexInfo: TYPE ~ ThreeDBasics.VertexInfo; VertexInfoSequence: TYPE ~ ThreeDBasics.VertexInfoSequence; VertexInfoProc: TYPE ~ ThreeDBasics.VertexInfoProc; ShapeClass: TYPE ~ ThreeDBasics.ShapeClass; ShapeProc: TYPE ~ ThreeDBasics.ShapeProc; ClipState: TYPE ~ ThreeDBasics.ClipState; OutCode: TYPE ~ ThreeDBasics.OutCode; AllOut: OutCode ~ ThreeDBasics.AllOut; NoneOut: OutCode ~ ThreeDBasics.NoneOut; FacingDir: TYPE ~ ThreeDBasics.FacingDir; FacingDirArray: TYPE ~ ARRAY [0..9) OF FacingDir; MidPtProc: TYPE ~ PROC[v0, v1: REF VertexInfo] RETURNS[REF VertexInfo]; LORA: TYPE = LIST OF REF ANY; maxDeviation: REAL _ 0.25; -- subdivision tolerance with antialiasing in pixels maxInteriorDev: REAL _ 0.25; -- (1.0) tolerance on internal edges maxJaggyDeviation: REAL _ 1.0; -- jaggy subdivision tolerance in pixels maxJaggyInteriorDev: REAL _ 1.0; -- (4.0) tolerance on internal edges closenessFactor: REAL _ 20.0; -- times maxDeviation gets clipping cutoff for straightness recurseLimit: NAT _ 14; -- safety valve on recursion stopIfStraight: BOOLEAN _ TRUE; -- set false to defeat termination algorithm stopOnDegenerate: BOOLEAN _ FALSE; -- signals on badly degenerate patches showLines: BOOLEAN _ FALSE; -- debug and pedagogical aid showCtlPts: BOOLEAN _ FALSE; -- debug and pedagogical aid refPt5: REF REAL _ NEW[REAL _ 0.5]; ShowCoords: PROC[poly: REF Patch, space: ATOM _ $Screen] RETURNS[list: LIST OF REF Pair] ~ { FOR i: CARD16 DECREASING IN [0..poly.nVtces) DO p: REF Pair; SELECT space FROM $Screen => p _ NEW[ Pair _ [ poly[i].coord.sx, poly[i].coord.sy ] ]; $Eye => p _ NEW[ Pair _ [ poly[i].coord.ex, poly[i].coord.ey ] ]; $Object => p _ NEW[ Pair _ [ poly[i].coord.x, poly[i].coord.y ] ]; ENDCASE; list _ CONS[p, list]; ENDLOOP; RETURN[list]; }; Sqr: PROCEDURE [number: REAL] RETURNS [REAL] ~ INLINE { RETURN[number * number]; }; CopyVtx: PROC[vtx: VertexInfo] RETURNS[vtxOut: REF VertexInfo] ~ { shape: REF ShapeInstance _ NARROW[ Atom.GetPropFromList[vtx.props, $Shape] ]; lerpProc: VertexInfoProc _ IF shape # NIL THEN shape.shadingClass.lerpVtxAux ELSE NIL; vtxOut _ ShapeUtilities.GetVertexInfo[]; vtxOut^ _ vtx; IF lerpProc # NIL THEN { -- copy vtx.aux, has to be done remotely since type not available data: LORA _ LIST[ vtx.aux, vtx.aux, refPt5, refPt5 ]; vtxOut^ _ lerpProc[ NIL, vtxOut^, data]; -- shoehorn into lerp form since its available } }; Sub: PROC[f, g: REAL] RETURNS[REAL] ~ { IF RealFns.AlmostEqual[f, g, -20] THEN RETURN [0.0] ELSE RETURN[f-g]; }; Sub1: PROC[f, g: REAL] RETURNS[REAL] ~ { result: REAL _ f-g; IF ABS[result] < ScanConvert.justNoticeable THEN RETURN [0.0] ELSE RETURN[result]; }; DiffTriple: PROC[v1, v2: Triple] RETURNS[Triple] ~ { RETURN[[Sub[v1.x, v2.x], Sub[v1.y, v2.y], Sub[v1.z, v2.z]]]; }; DiffPosns: PROC[vtx1, vtx2: Vertex, space: ATOM _ NIL] RETURNS[Triple] ~ { SELECT space FROM $Eye => RETURN[[Sub[vtx1.ex, vtx2.ex], Sub[vtx1.ey, vtx2.ey], Sub[vtx1.ez, vtx2.ez]]]; $Screen=> RETURN[[Sub1[vtx1.sx, vtx2.sx], Sub1[vtx1.sy, vtx2.sy], Sub1[vtx1.sz, vtx2.sz]]]; ENDCASE => -- object space RETURN[[Sub[vtx1.x, vtx2.x], Sub[vtx1.y, vtx2.y], Sub[vtx1.z, vtx2.z]]]; }; VtxDisplayMidPt: MidPtProc ~ { shape: REF ShapeInstance _ NARROW[ Atom.GetPropFromList[v0.props, $Shape] ]; lerpProc: VertexInfoProc _ IF shape # NIL THEN shape.shadingClass.lerpVtxAux ELSE NIL; v: REF VertexInfo _ ShapeUtilities.GetVertexInfo[]; v.coord.sx _ (v0.coord.sx + v1.coord.sx) / 2; -- for position on screen v.coord.sy _ (v0.coord.sy + v1.coord.sy) / 2; v.coord.sz _ (v0.coord.sz + v1.coord.sz) / 2; v.coord.ex _ (v0.coord.ex + v1.coord.ex) / 2; -- for normal-vector shading v.coord.ey _ (v0.coord.ey + v1.coord.ey) / 2; v.coord.ez _ (v0.coord.ez + v1.coord.ez) / 2; v.shade.r _ (v0.shade.r + v1.shade.r) / 2; -- for color-per-vertex (could be avoided) v.shade.g _ (v0.shade.g + v1.shade.g) / 2; v.shade.b _ (v0.shade.b + v1.shade.b) / 2; IF shape.shadingClass.texture # NIL THEN { v.coord.x _ (v0.coord.x + v1.coord.x) / 2; v.coord.y _ (v0.coord.y + v1.coord.y) / 2; v.coord.z _ (v0.coord.z + v1.coord.z) / 2; }; IF lerpProc # NIL THEN { -- get auxiliary info from supplied proc data: LORA _ LIST[ v0.aux, v1.aux, refPt5, refPt5 ]; v^ _ lerpProc[ NIL, v^, data]; } ELSE v.aux _ v0.aux; v.props _ v0.props; RETURN[v]; }; TooClose: PROC[ context: REF Context, v: Vertex, outCode: OutCode, tol: REAL ] RETURNS[BOOLEAN] ~ { maxDist: REAL _ 0.0; IF v.sz = 0.0 THEN RETURN [FALSE]; -- invalid screen coord, ignore IF outCode.left THEN maxDist _ MAX[maxDist, v.sx - context.viewPort.x]; IF outCode.right THEN maxDist _ MAX[maxDist, context.viewPort.w + context.viewPort.x - v.sx]; IF outCode.bottom THEN maxDist _ MAX[maxDist, v.sy - context.viewPort.y]; IF outCode.top THEN maxDist _ MAX[maxDist, context.viewPort.h + context.viewPort.y - v.sy]; IF maxDist < tol * closenessFactor THEN RETURN[TRUE] ELSE RETURN[FALSE]; }; PutPropSafely: PROC[propList: Atom.PropList, prop, val: REF ANY] RETURNS[Atom.PropList] ~{ newProps: Atom.PropList _ NIL; FOR list: Atom.PropList _ propList, list.rest UNTIL list = NIL DO -- new proplist element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; newProps _ CONS[element, newProps]; ENDLOOP; RETURN[ Atom.PutPropOnList[ newProps, prop, val ] ]; }; RemPropSafely: PROC[ propList: Atom.PropList, prop: REF ANY ] RETURNS[Atom.PropList] ~ { newProps: Atom.PropList _ NIL; FOR list: Atom.PropList _ propList, list.rest UNTIL list = NIL DO -- new proplist element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; newProps _ CONS[element, newProps]; ENDLOOP; RETURN[ Atom.RemPropFromList[ newProps, prop ] ]; }; MakeStraight: PROC[ v0, v1, vMid: VertexInfo ] RETURNS[VertexInfo] ~ { shape: REF ShapeInstance _ NARROW[ Atom.GetPropFromList[v0.props, $Shape] ]; lerpProc: VertexInfoProc _ IF shape # NIL THEN shape.shadingClass.lerpVtxAux ELSE NIL; a, b, alpha: REAL; mag: REAL _ RealFns.SqRt[ Sqr[v1.coord.sx - v0.coord.sx] + Sqr[v1.coord.sy - v0.coord.sy] ]; IF mag < ScanConvert.justNoticeable -- effectively invisible detail THEN { vMid.coord _ v0.coord; vMid.shade _ v0.shade; RETURN[vMid]; }; alpha _ ( (vMid.coord.sx - v0.coord.sx) * (v1.coord.sx - v0.coord.sx) -- vMid-v0 dot v1-v0 + (vMid.coord.sy - v0.coord.sy) * (v1.coord.sy - v0.coord.sy) ) / Sqr[mag]; a _ 1.0 - alpha; b _ alpha; vMid.coord.sx _ a * v0.coord.sx + b * v1.coord.sx ; -- screen coords (for scan conversion) vMid.coord.sy _ a * v0.coord.sy + b * v1.coord.sy ; vMid.coord.sz _ a * v0.coord.sz + b * v1.coord.sz ; vMid.shade.r _ a * v0.shade.r + b * v1.shade.r ; -- surface color vMid.shade.g _ a * v0.shade.g + b * v1.shade.g ; vMid.shade.b _ a * v0.shade.b + b * v1.shade.b ; IF shape.shadingClass.texture # NIL THEN { -- original coords (for solid texture) vMid.coord.x _ a * v0.coord.x + b * v1.coord.x ; vMid.coord.y _ a * v0.coord.y + b * v1.coord.y ; vMid.coord.z _ a * v0.coord.z + b * v1.coord.z ; }; IF lerpProc # NIL THEN { -- get auxiliary info from supplied proc data: LORA _ LIST[ v0.aux, v1.aux, NEW[REAL _ a], NEW[REAL _ b] ]; vMid _ lerpProc[ NIL, vMid, data]; }; RETURN[vMid]; }; SetStraight: PROC[ p: REF Patch, v0, v1, v2, v3: NAT] ~ { p[v1] _ MakeStraight[ p[v0], p[v3], p[v1] ]; p[v2] _ MakeStraight[ p[v0], p[v3], p[v2] ]; p[v0].props _ PutPropSafely[p[v0].props, $Straight, $Itis]; }; StraightWithin: PROC[ context: REF Context, p: REF Patch, v0, v1, v2, v3: NAT, lilTol, bigTol: REAL] RETURNS[BOOLEAN] ~ { StraightenUp: PROC[] ~ { p[v0].props _ PutPropSafely[p[v0].props, $Straight, $DoIt]; }; InteriorEdge: PROC[] RETURNS[BOOLEAN] ~ { PolyNo: PROC[v: INTEGER] RETURNS[NAT] ~ { i: NAT _ MAX[v / 4 -1 , 0]; j: NAT _ MAX[v MOD 4 -1 , 0]; RETURN[ i*3 + j ]; }; facingDir: FacingDir; subDirs: REF FacingDirArray _ NARROW[ Atom.GetPropFromList[p.props, $FacingDirArray] ]; IF subDirs = NIL THEN RETURN[FALSE]; facingDir _ subDirs[PolyNo[v0]]; IF subDirs[PolyNo[v1]] # facingDir THEN RETURN[FALSE]; IF subDirs[PolyNo[v2]] # facingDir THEN RETURN[FALSE]; IF subDirs[PolyNo[v3]] # facingDir THEN RETURN[FALSE]; IF facingDir = undetermined THEN RETURN[FALSE]; RETURN[TRUE]; }; DistOffEdge: PROC[v: Vertex, line: Ray] RETURNS[REAL] ~ { ptOnEdge: Triple _ ShapeUtilities.XfmPtToDisplay[ context, G3dVector.NearestToLine[line, [v.ex, v.ey, v.ez]] ]; vs: Triple _ ShapeUtilities.XfmPtToDisplay[ context, [v.ex, v.ey, v.ez] ]; RETURN[ RealFns.SqRt[ Sqr[ptOnEdge.x - vs.x] + Sqr[ptOnEdge.y - vs.y] ] ]; }; dist1, dist2, dist3, baseDist, a, b: REAL _ 0.0; reversed: BOOLEAN _ FALSE; shape: REF ShapeInstance; IF Atom.GetPropFromList[p[v0].props, $Straight] # NIL THEN RETURN[TRUE]; a _ p[v3].coord.sy - p[v0].coord.sy; b _ p[v3].coord.sx - p[v0].coord.sx; baseDist _ RealFns.SqRt[a*a + b*b]; IF baseDist > ScanConvert.justNoticeable THEN { a _ a/baseDist; b _ b/baseDist; -- get normalized distances from v0-v3 dist1 _ a * (p[v1].coord.sx - p[v0].coord.sx) + b * (p[v0].coord.sy - p[v1].coord.sy); IF ABS[dist1] > bigTol THEN RETURN[FALSE]; dist2 _ a * (p[v2].coord.sx - p[v0].coord.sx) + b * (p[v0].coord.sy - p[v2].coord.sy); IF ABS[dist2] > bigTol THEN RETURN[FALSE]; shape _ NARROW[ Atom.GetPropFromList[p.props, $Shape] ]; IF shape.shadingClass.texture # NIL THEN { -- watch for perspective depth distortion point: Triple _ [p[v0].coord.ex, p[v0].coord.ey, p[v0].coord.ez]; line: Ray _ [ point, DiffPosns[p[v3].coord, p[v0].coord, $Eye] ]; dist1: REAL _ DistOffEdge[p[v1].coord, line]; dist2: REAL _ DistOffEdge[p[v2].coord, line]; IF dist1 > bigTol OR dist2 > bigTol THEN RETURN[FALSE]; }; }; SELECT TRUE FROM MAX[dist1, dist2] < lilTol => { -- inside minimum deviation used onshape boundary StraightenUp[]; RETURN[ TRUE ]; }; p.dir # undetermined => { StraightenUp[]; RETURN[ TRUE ]; }; -- interior patch InteriorEdge[] => { StraightenUp[]; RETURN[ TRUE ]; }; -- interior edge ENDCASE => RETURN[ FALSE ]; }; PatchSort: PROC[ context: REF Context, p0, p1, p2, p3: REF Patch] RETURNS[REF Patch, REF Patch, REF Patch, REF Patch] ~ { z: ARRAY[0..4) OF REAL; pOut: ARRAY[0..4) OF REF Patch; z[0] _ (p0[0].coord.ez + p0[12].coord.ez + p0[15].coord.ez + p0[3].coord.ez)/4; pOut[0] _ p0; z[1] _ (p1[0].coord.ez + p1[12].coord.ez + p1[15].coord.ez + p1[3].coord.ez)/4; pOut[1] _ p1; z[2] _ (p2[0].coord.ez + p2[12].coord.ez + p2[15].coord.ez + p2[3].coord.ez)/4; pOut[2] _ p2; z[3] _ (p3[0].coord.ez + p3[12].coord.ez + p3[15].coord.ez + p3[3].coord.ez)/4; pOut[3] _ p3; FOR i: NAT IN [1..4) DO FOR j: NAT DECREASING IN [0..i) DO -- sort to increasing depth order IF z[j+1] < z[j] THEN { t: REAL _ z[j+1]; p: REF Patch _ pOut[j+1]; z[j+1] _ z[j]; pOut[j+1] _ pOut[j]; z[j] _ t; pOut[j] _ p; }; ENDLOOP; ENDLOOP; IF context.antiAliasing THEN RETURN[ pOut[0], pOut[1], pOut[2], pOut[3] ] ELSE RETURN[ pOut[3], pOut[2], pOut[1], pOut[0] ]; }; ValidatePatchShape: ShapeProc ~ { -- IF shape.vtcesInValid THEN { shape.clipState _ ShapeUtilities.XfmToEyeSpace[ context, shape ]; IF shape.surface # NIL THEN { -- get clipping info for patches patch: REF PtrPatchSequence _ NARROW[shape.surface]; FOR i: NAT IN [0..shape.numSurfaces) DO IF patch[i] # NIL THEN IF shape.clipState = in THEN patch[i].clipState _ in -- unclipped, inside ELSE IF shape.clipState = clipped -- evaluate clipping tags THEN SurfaceRender.GetPtrPatchClipState[ shape, patch[i] ] ELSE patch[i].clipState _ out; ENDLOOP; }; shape.vtcesInValid _ FALSE; }; shape.shadingInValid _ FALSE; RETURN[shape]; }; InitClasses: PROC[] ~ { -- register procedures for basic surface types standardClass: ShapeClass _ ThreeDBasics.GetSurfaceType[$ConvexPolygon]; standardClass.type _ $Bezier; standardClass.validate _ ValidatePatchShape; standardClass.displayPatch _ BezierDisplay; ThreeDBasics.RegisterSurfaceType[standardClass, $Bezier]; standardClass.type _ $BSpline; standardClass.validate _ ValidatePatchShape; standardClass.displayPatch _ BSplineDisplay; ThreeDBasics.RegisterSurfaceType[standardClass, $BSpline]; standardClass.type _ $NonConvexPolygon; standardClass.validate _ SurfaceRender.ValidatePolyhedron; standardClass.displayPatch _ NonConvexDisplay; ThreeDBasics.RegisterSurfaceType[standardClass, $NonConvexPolygon]; }; BezierDisplay: PatchProc ~ { shape: REF ShapeInstance _ NARROW[ Atom.GetPropFromList[patch.props, $Shape] ]; SELECT shape.shadingClass.shadingType FROM $Lines => { [] _ BezierDisplayLines[context, patch]; RETURN[NIL]; }; $CtlPts => { [] _ BezierDisplayCtrlPts[context, patch]; RETURN[NIL]; }; ENDCASE; patch _ BezierClipState[context, patch]; IF patch.nVtces = 16 -- Divide till all outside patch edges are straight or recursion exceeded THEN BezierPatchDisplay[context, patch, 0] ELSE IF patch.nVtces = 10 THEN BezierTriangleDisplay[ context, patch, MIN[6, recurseLimit] ]; RETURN[NIL]; -- end of the line, no patch returned }; BezierPatchDisplay: PROC[ context: REF Context, p: REF Patch, level: NAT] ~ { allStraight: BOOLEAN _ TRUE; lilTol: REAL _ IF context.antiAliasing THEN maxDeviation ELSE maxJaggyDeviation; bigTol: REAL _ IF context.antiAliasing THEN maxInteriorDev ELSE maxJaggyInteriorDev; IF context.stopMe^ THEN RETURN[]; -- shut down if stop signal received IF p.clipState = out THEN RETURN[]; IF p.oneSided AND p.dir = back THEN RETURN[]; -- backfacing on closed surface IF p.clipState = undetermined THEN allStraight _ FALSE ELSE { -- Straightness test on patch boundary, if straight enough, force straightness IF NOT StraightWithin[context, p, 0, 4, 8,12, lilTol, bigTol] THEN allStraight _ FALSE; IF NOT StraightWithin[context, p,12,13,14,15, lilTol, bigTol] THEN allStraight _ FALSE; IF NOT StraightWithin[context, p,15,11, 7, 3, lilTol, bigTol] THEN allStraight _ FALSE; IF NOT StraightWithin[context, p, 3, 2, 1, 0, lilTol, bigTol] THEN allStraight _ FALSE; }; IF stopIfStraight AND allStraight OR level >= recurseLimit THEN IF showCtlPts -- outer edges straight, display as polygon THEN p _ BezierDisplayCtrlPts[context, p] ELSE { p _ PolygonFromBezierPatch[p]; -- construct polygon ShapeUtilities.ShadePoly[context, p]; IF showLines THEN p.type _ $PolyLine; p _ SurfaceRender.OutputPolygon[context, p]; -- display } ELSE { -- not straight enough, subdivide and recurse p0, p1, p2, p3: REF Patch; [p0, p1, p2, p3] _ BezierPatchDivide[ context, p, VtxDisplayMidPt ]; -- subdivide IF NOT context.depthBuffering THEN [p0, p1, p2, p3] _ PatchSort[ context, p0, p1, p2, p3]; -- sort to display order BezierPatchDisplay[context, p0, level+1]; BezierPatchDisplay[context, p1, level+1]; BezierPatchDisplay[context, p2, level+1]; BezierPatchDisplay[context, p3, level+1]; }; IF p # NIL THEN ShapeUtilities.ReleasePatch[p]; -- end of life for patch }; BezierTriangleDisplay: PROC[ context: REF Context, p: REF Patch, divisions: NAT] ~ { MdPt: PROC[v0, v1, v2: VertexInfo, r, s, t: REAL] RETURNS[VertexInfo] ~ { shape: REF ShapeInstance _ NARROW[ Atom.GetPropFromList[v0.props, $Shape] ]; lerpProc: VertexInfoProc _ IF shape # NIL THEN shape.shadingClass.lerpVtxAux ELSE NIL; v: VertexInfo; v.coord.sx _ r * v0.coord.sx + s * v1.coord.sx + t * v2.coord.sx; -- for position on screen v.coord.sy _ r * v0.coord.sy + s * v1.coord.sy + t * v2.coord.sy; v.coord.sz _ r * v0.coord.sz + s * v1.coord.sz + t * v2.coord.sz; v.coord.ex _ r * v0.coord.ex + s * v1.coord.ex + t * v2.coord.ex; -- for nml-vector shading v.coord.ey _ r * v0.coord.ey + s * v1.coord.ey + t * v2.coord.ey; v.coord.ez _ r * v0.coord.ez + s * v1.coord.ez + t * v2.coord.ez; v.shade.r _ r * v0.shade.r + s * v1.shade.r + t * v2.shade.r; -- clr/vtx (could be avoided) v.shade.g _ r * v0.shade.g + s * v1.shade.g + t * v2.shade.g; v.shade.b _ r * v0.shade.b + s * v1.shade.b + t * v2.shade.b; IF shape.shadingClass.texture # NIL THEN { v.coord.x _ r * v0.coord.x + s * v1.coord.x + t * v2.coord.x; v.coord.y _ r * v0.coord.y + s * v1.coord.y + t * v2.coord.y; v.coord.z _ r * v0.coord.z + s * v1.coord.z + t * v2.coord.z; }; IF lerpProc # NIL THEN { -- get auxiliary info from supplied proc data: LORA _ LIST[ v0.aux, v1.aux, NEW[REAL _ r], NEW[REAL _ s] ]; v _ lerpProc[ NIL, v, data]; data _ LIST[ v.aux, v2.aux, NEW[REAL _ r+s], NEW[REAL _ t] ]; v _ lerpProc[ NIL, v, data]; } ELSE v.aux _ v0.aux; v.props _ v0.props; RETURN[v]; }; EvalTriangle: PROC[p: REF Patch, r, s, t: REAL] RETURNS[VertexInfo] ~ { p1: ARRAY[0..6) OF VertexInfo; p2: ARRAY[0..3) OF VertexInfo; p3: VertexInfo; p1[0] _ MdPt[p[1], p[8], p[0], r,s,t]; -- p1[0,0,2] _ r*p[1,0,2] + s*p[0,1,2] + t*p[0,0,3]; p1[2] _ MdPt[p[3], p[4], p[2], r,s,t]; -- p1[2,0,0] _ r*p[3,0,0] + s*p[2,1,0] + t*p[2,0,1]; p1[4] _ MdPt[p[5], p[6], p[7], r,s,t]; -- p1[0,2,0] _ r*p[1,2,0] + s*p[0,3,0] + t*p[0,2,1]; p1[1] _ MdPt[p[2], p[9], p[1], r,s,t]; -- p1[1,0,1] _ r*p[2,0,1] + s*p[1,1,1] + t*p[1,0,2]; p1[3] _ MdPt[p[4], p[5], p[9], r,s,t]; -- p1[1,1,0] _ r*p[2,1,0] + s*p[1,2,0] + t*p[1,1,1]; p1[5] _ MdPt[p[9], p[7], p[8], r,s,t]; -- p1[0,1,1] _ r*p[1,1,1] + s*p[0,2,1] + t*p[0,1,2]; p2[0] _ MdPt[p1[1], p1[5], p1[0], r,s,t]; -- p2[0,0,1] _ r*p[1,0,1] + s*p[0,1,1] + t*p[0,0,2]; p2[1] _ MdPt[p1[2], p1[3], p1[1], r,s,t]; -- p2[1,0,0] _ r*p[2,0,0] + s*p[1,1,0] + t*p[1,0,1]; p2[2] _ MdPt[p1[3], p1[4], p1[5], r,s,t]; -- p2[0,1,0] _ r*p[1,1,0] + s*p[0,2,0] + t*p[0,1,1]; p3 _ MdPt[p2[1], p2[2], p2[0], r,s,t]; -- p3[0,0,0] _ r*p[1,0,0] + s*p[0,1,0] + t*p[0,0,1]; RETURN[p3]; }; steps: NAT _ INTEGER[Basics.BITSHIFT[ 1, divisions ]]; rotateBy: NAT; IF context.stopMe^ THEN RETURN[]; -- shut down if stop signal received IF p.clipState = out THEN RETURN[]; IF p.oneSided AND p.dir = back THEN RETURN[]; -- backfacing on closed surface IF p[6].coord.ez > p[3].coord.ez -- Reorder outer control points to sort for view THEN IF p[6].coord.ez > p[0].coord.ez THEN rotateBy _ 0 ELSE rotateBy _ 3 ELSE IF p[3].coord.ez > p[0].coord.ez THEN rotateBy _ 6 ELSE rotateBy _ 3; FOR i: NAT IN [0..3) DO -- put vtx 6 farthest from viewer tmpVtx: VertexInfo; SELECT rotateBy FROM 3 => { tmpVtx _ p[i]; p[i] _ p[i+3]; p[i+3] _ p[i+6]; p[i+6] _ tmpVtx }; 6 => { tmpVtx _ p[i]; p[i] _ p[i+6]; p[i+6] _ p[i+3]; p[i+3] _ tmpVtx }; ENDCASE; -- no changes needed if 6 already farthest ENDLOOP; FOR i: NAT IN [1..steps] DO -- walk across patch with barycentric coordinates ls: REAL _ IF context.antiAliasing THEN 1.0 * (i-1) / steps ELSE 1.0 * (steps-i+1) / steps; s: REAL _ IF context.antiAliasing THEN 1.0 * i / steps ELSE 1.0 * (steps-i) / steps; FOR j: NAT IN [1..i] DO lr: REAL _ 1.0 * (j-1) / steps; -- step from r=0 to r=s r: REAL _ 1.0 * j / steps; tp: REF Patch _ ShapeUtilities.GetPatch[3]; -- will be released by action proc tp.type _ $ConvexPolygon; tp.oneSided _ p.oneSided; tp.nVtces _ 3; tp.clipState _ p.clipState; tp.dir _ p.dir; tp.props _ p.props; tp[0] _ EvalTriangle[p, lr, ls, 1.0 - lr - ls]; tp[1] _ EvalTriangle[p, r, s, 1.0 - r - s]; tp[2] _ EvalTriangle[p, lr, s, 1.0 - lr - s]; ShapeUtilities.ShadePoly[context, tp]; IF showLines THEN tp.type _ $PolyLine; tp _ SurfaceRender.OutputPolygon[context, tp]; -- display IF j # i THEN { ttp: REF Patch _ ShapeUtilities.GetPatch[3]; -- will be released by action proc ttp.type _ $ConvexPolygon; ttp.oneSided _ p.oneSided; ttp.nVtces _ 3; ttp.clipState _ p.clipState; ttp.dir _ p.dir; ttp.props _ p.props; ttp[0] _ EvalTriangle[p, lr, ls, 1.0 - lr - ls]; ttp[1] _ EvalTriangle[p, r, ls, 1.0 - r - ls]; ttp[2] _ EvalTriangle[p, r, s, 1.0 - r - s]; ShapeUtilities.ShadePoly[context, ttp]; IF showLines THEN ttp.type _ $PolyLine; ttp _ SurfaceRender.OutputPolygon[context, ttp]; -- display }; ENDLOOP; ENDLOOP; IF p # NIL THEN ShapeUtilities.ReleasePatch[p]; -- end of life for patch }; BezierDisplayLines: PatchProc ~ { EvalCoords: PROC[ context: REF Context, patch: REF Patch, v0, v1, v2, v3: NAT, numPts: NAT _ 8 ] RETURNS [outP: REF Patch] ~ { clipState: ClipState; IF patch.clipState = in -- get clipState of convex hull THEN clipState _ in ELSE { outCode: OutCode _ LOOPHOLE[ Basics.BITOR[ Basics.BITOR[ LOOPHOLE[patch[v0].coord.clip], LOOPHOLE[patch[v1].coord.clip] ], Basics.BITOR[ LOOPHOLE[patch[v2].coord.clip], LOOPHOLE[patch[v3].coord.clip] ] ], OutCode ]; IF outCode = NoneOut THEN clipState _ in ELSE { outCode _ LOOPHOLE[ Basics.BITAND[ Basics.BITAND[ LOOPHOLE[patch[v0].coord.clip], LOOPHOLE[patch[v1].coord.clip] ], Basics.BITAND[ LOOPHOLE[patch[v2].coord.clip], LOOPHOLE[patch[v3].coord.clip] ] ], OutCode ]; IF outCode # NoneOut THEN clipState _ out ELSE clipState _ clipped; }; }; outP _ ShapeUtilities.GetPatch[numPts]; -- will be released by action proc FOR i: NAT IN [0..numPts) DO t: REAL _ Real.Float[i] / (numPts-1); t2: REAL _ t * t; t3: REAL _ t2 * t; f0: REAL _ -1.0*t3 + 3.0*t2 - 3.0*t + 1; f1: REAL _ 3.0*t3 - 6.0*t2 + 3.0*t; f2: REAL _ -3.0*t3 + 3.0*t2; f3: REAL _ 1.0*t3; IF clipState # in OR context.antiAliasing THEN { outP[i].coord.ex _ f0*patch[v0].coord.ex + f1*patch[v1].coord.ex + f2*patch[v2].coord.ex + f3*patch[v3].coord.ex; outP[i].coord.ey _ f0*patch[v0].coord.ey + f1*patch[v1].coord.ey + f2*patch[v2].coord.ey + f3*patch[v3].coord.ey; outP[i].coord.ez _ f0*patch[v0].coord.ez + f1*patch[v1].coord.ez + f2*patch[v2].coord.ez + f3*patch[v3].coord.ez; IF clipState # in THEN outP[i].coord.clip _ ShapeUtilities.GetClipCodeForPt[ context, [outP[i].coord.ex, outP[i].coord.ey, outP[i].coord.ez] ]; IF context.antiAliasing THEN { outP[i].shade.r _ f0*patch[v0].shade.r + f1*patch[v1].shade.r + f2*patch[v2].shade.r + f3*patch[v3].shade.r; outP[i].shade.g _ f0*patch[v0].shade.g + f1*patch[v1].shade.g + f2*patch[v2].shade.g + f3*patch[v3].shade.g; outP[i].shade.b _ f0*patch[v0].shade.b + f1*patch[v1].shade.b + f2*patch[v2].shade.b + f3*patch[v3].shade.b; }; } ELSE { outP[i].coord.sx _ f0*patch[v0].coord.sx + f1*patch[v1].coord.sx + f2*patch[v2].coord.sx + f3*patch[v3].coord.sx; outP[i].coord.sy _ f0*patch[v0].coord.sy + f1*patch[v1].coord.sy + f2*patch[v2].coord.sy + f3*patch[v3].coord.sy; outP[i].coord.sz _ f0*patch[v0].coord.sz + f1*patch[v1].coord.sz + f2*patch[v2].coord.sz + f3*patch[v3].coord.sz; }; outP[i].coord.x _ f0*patch[v0].coord.x + f1*patch[v1].coord.x -- needed for display lists + f2*patch[v2].coord.x + f3*patch[v3].coord.x; outP[i].coord.y _ f0*patch[v0].coord.y + f1*patch[v1].coord.y + f2*patch[v2].coord.y + f3*patch[v3].coord.y; outP[i].coord.z _ f0*patch[v0].coord.z + f1*patch[v1].coord.z + f2*patch[v2].coord.z + f3*patch[v3].coord.z; outP[i].shade.er _ f0*patch[v0].shade.er + f1*patch[v1].shade.er + f2*patch[v2].shade.er + f3*patch[v3].shade.er; outP[i].shade.eg _ f0*patch[v0].shade.eg + f1*patch[v1].shade.eg + f2*patch[v2].shade.eg + f3*patch[v3].shade.eg; outP[i].shade.eb _ f0*patch[v0].shade.eb + f1*patch[v1].shade.eb + f2*patch[v2].shade.eb + f3*patch[v3].shade.eb; ENDLOOP; outP.type _ $PolyLine; outP.props _ patch.props; outP.clipState _ clipState; outP.nVtces _ numPts; }; path: REF Patch; IF patch.nVtces = 16 THEN { path _ EvalCoords[ context, patch, 0, 1, 2, 3 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch,12,13,14,15 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 0, 4, 8,12 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 3, 7,11,15 ]; [] _ SurfaceRender.OutputPolygon[context, path]; } ELSE IF patch.nVtces = 10 THEN { path _ EvalCoords[ context, patch, 0, 1, 2, 3 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 3, 4, 5, 6 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 6, 7, 8, 0 ]; [] _ SurfaceRender.OutputPolygon[context, path]; }; IF data # $DontRelease THEN ShapeUtilities.ReleasePatch[patch]; -- end of life for patch RETURN[NIL]; -- end of the line, no patch returned }; BezierDisplayCtrlPts: PatchProc ~ { EvalCoords: PROC[ context: REF Context, patch: REF Patch, v0, v1, v2, v3: NAT, numPts: NAT _ 4 ] RETURNS [outP: REF Patch] ~ { clipState: ClipState; IF patch.clipState = in -- get clipState of convex hull THEN clipState _ in ELSE { outCode: OutCode _ LOOPHOLE[ Basics.BITOR[ Basics.BITOR[ LOOPHOLE[patch[v0].coord.clip], LOOPHOLE[patch[v1].coord.clip] ], Basics.BITOR[ LOOPHOLE[patch[v2].coord.clip], LOOPHOLE[patch[v3].coord.clip] ] ], OutCode ]; IF outCode = NoneOut THEN clipState _ in ELSE { outCode _ LOOPHOLE[ Basics.BITAND[ Basics.BITAND[ LOOPHOLE[patch[v0].coord.clip], LOOPHOLE[patch[v1].coord.clip] ], Basics.BITAND[ LOOPHOLE[patch[v2].coord.clip], LOOPHOLE[patch[v3].coord.clip] ] ], OutCode ]; IF outCode # NoneOut THEN clipState _ out ELSE clipState _ clipped; }; }; outP _ ShapeUtilities.GetPatch[4]; -- will be released by action proc outP[0] _ patch[v0]; outP[1] _ patch[v1]; outP[2] _ patch[v2]; outP[3] _ patch[v3]; outP.type _ $PolyLine; outP.props _ patch.props; outP.clipState _ clipState; outP.nVtces _ numPts; }; path: REF Patch; IF patch.nVtces = 16 THEN { path _ EvalCoords[ context, patch, 0, 1, 2, 3 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 4, 5, 6, 7 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 8, 9,10,11 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch,12,13,14,15 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 0, 4, 8,12 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 1, 5, 9,13 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 2, 6,10,14 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 3, 7,11,15 ]; [] _ SurfaceRender.OutputPolygon[context, path]; } ELSE IF patch.nVtces = 10 THEN { path _ EvalCoords[ context, patch, 0, 1, 2, 3 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 3, 4, 5, 6 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 6, 7, 8, 0 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 9, 8, 1, 9 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 9, 7, 4, 9 ]; [] _ SurfaceRender.OutputPolygon[context, path]; path _ EvalCoords[ context, patch, 9, 5, 7, 9 ]; [] _ SurfaceRender.OutputPolygon[context, path]; }; IF data # $DontRelease THEN ShapeUtilities.ReleasePatch[patch]; -- end of life for patch RETURN[NIL]; -- end of the line, no patch returned }; PolygonFromBezierPatch: PROC[p: REF Patch] RETURNS [REF Patch] ~ { leftCrnr: ARRAY [0..16) OF NAT _ [12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 3]; rghtCrnr: ARRAY [0..16) OF NAT _ [3, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12]; GetNorm: PROC[v, lft, nxtLft, rgt, nxtRgt: NAT] RETURNS[VertexInfo] ~ { normal: Triple; d1: Triple _ DiffPosns[ p[lft].coord, p[v].coord, $Eye ]; -- results zero if < 6 sig. digits d2: Triple _ DiffPosns[ p[rgt].coord, p[v].coord, $Eye ]; IF G3dVector.Null[ d1 ] THEN d1 _ DiffPosns[ p[nxtLft].coord, p[v].coord, $Eye ]; IF G3dVector.Null[ d2 ] THEN d2 _ DiffPosns[ p[nxtRgt].coord, p[v].coord, $Eye ]; normal _ G3dVector.Normalize[ G3dVector.Cross[d2, d1 ] ]; IF NOT G3dVector.Null[ DiffTriple[ d2, G3dVector.Add[d2, normal] ] ] THEN [p[v].shade.exn, p[v].shade.eyn, p[v].shade.ezn] _ normal -- significant length ELSE IF p.nVtces = 16 THEN { -- use polygon corners, too many degenerate knots d1 _ DiffPosns[ p[leftCrnr[v]].coord, p[v].coord, $Eye ]; d2 _ DiffPosns[ p[rghtCrnr[v]].coord, p[v].coord, $Eye ]; IF G3dVector.Null[ d1 ] THEN d1 _ DiffPosns[ p[leftCrnr[leftCrnr[v]]].coord, p[v].coord, $Eye ]; IF G3dVector.Null[ d2 ] THEN d2 _ DiffPosns[ p[rghtCrnr[rghtCrnr[v]]].coord, p[v].coord, $Eye ]; normal _ G3dVector.Normalize[ G3dVector.Cross[d2, d1 ] ]; IF NOT G3dVector.Null[ DiffTriple[ d2, G3dVector.Add[d2, normal] ] ] THEN [p[v].shade.exn, p[v].shade.eyn, p[v].shade.ezn] _ normal ELSE [p[v].shade.exn, p[v].shade.eyn, p[v].shade.ezn] _ G3dBasic.origin; } ELSE [p[v].shade.exn, p[v].shade.eyn, p[v].shade.ezn] _ G3dBasic.origin; RETURN [p[v]]; }; outputType: ATOM _ NARROW[ Atom.GetPropFromList[ p.props, $InterimPatchType ] ]; IF outputType = NIL THEN outputType _ $ConvexPolygon; p.type _ outputType; -- type of output patch IF p.nVtces = 16 THEN { p[0] _ GetNorm[v: 0, lft: 1, nxtLft: 7, rgt: 4, nxtRgt: 13]; -- use next control pt and p[3] _ GetNorm[v: 3, lft: 7, nxtLft: 14, rgt: 2, nxtRgt: 4]; -- pt around next corner p[15] _ GetNorm[v: 15, lft: 14, nxtLft: 8, rgt: 11, nxtRgt: 2]; -- to catch degeneracies p[12] _ GetNorm[v: 12, lft: 8, nxtLft: 1, rgt: 13, nxtRgt: 11]; p.nVtces _ 4; -- copy corners (p[0], p[3] stay put) p[1] _ CopyVtx[ p[12] ]^; p[2] _ CopyVtx[ p[15] ]^; } ELSE IF p.nVtces = 10 THEN { -- triangular patches taken clockwise, last pt in middle p[0] _ GetNorm[v: 0, lft: 1, nxtLft: 4, rgt: 8, nxtRgt: 5]; -- use next control pt and p[3] _ GetNorm[v: 3, lft: 4, nxtLft: 7, rgt: 2, nxtRgt: 8]; -- pt around next corner p[6] _ GetNorm[v: 6, lft: 5, nxtLft: 2, rgt: 7, nxtRgt: 1]; -- to catch degeneracies p.nVtces _ 3; -- copy corners (p[0] stays put) p[1] _ CopyVtx[ p[3] ]^; p[2] _ CopyVtx[ p[6] ]^; }; FOR i: NAT IN [0..p.nVtces) DO -- check for null normals (aligned vertices at corner) IF G3dVector.Null[ [p[i].shade.exn, p[i].shade.eyn, p[i].shade.ezn] ] THEN { j: NAT _ (i+1) MOD p.nVtces; -- found a null normal, try next vertex in order p[i].shade.exn _ p[j].shade.exn; p[i].shade.eyn _ p[j].shade.eyn; p[i].shade.ezn _ p[j].shade.ezn; IF G3dVector.Null[ [p[i].shade.exn, p[i].shade.eyn, p[i].shade.ezn] ] THEN { IF stopOnDegenerate THEN SIGNAL ThreeDBasics.Error[[$MisMatch, "Very degenerate Patch"]]; p.nVtces _ 2; -- 2 null nmls, polygon will be ignored by scan converter RETURN[p]; }; }; ENDLOOP; IF showLines -- extra vertex closes path for lines THEN { p[p.nVtces] _ CopyVtx[ p[0] ]^; p.nVtces _ p.nVtces+1; }; RETURN[p]; }; BezierBackFacing: PROC[context: REF Context, p: REF Patch] RETURNS[BOOLEAN] ~ { facing: FacingDir; back, front, undetermined: BOOLEAN _ FALSE; subdir: FacingDirArray; IF p.dir = front THEN RETURN[FALSE]; IF p.dir = back THEN RETURN[TRUE]; FOR i: NAT IN [0..3) DO FOR j: NAT IN [0..3) DO patch: REF Patch _ ShapeUtilities.GetPatch[3]; patch.type _ $ConvexPolygon; IF p.nVtces = 16 THEN { k: NAT _ 4*i + j; -- index of lower left corner patch[0] _ p[k]; patch[1] _ p[k + 4]; patch[2] _ p[k + 1]; } ELSE IF p.nVtces = 10 THEN { -- triangular patch k: NAT _ 3*j; SELECT i FROM 0 => { patch[0] _ p[k]; patch[1] _ p[k+1]; patch[2] _ p[(k+8) MOD 9]; }; 1 => { patch[0] _ p[k+1]; patch[1] _ p[k+2]; patch[2] _ p[9]; }; 2 => { patch[0] _ p[k+1]; patch[1] _ p[9]; patch[2] _ p[(k+8) MOD 9]; }; ENDCASE; }; facing _ ShapeUtilities.BackFacing[ context, patch, TRUE ! ThreeDBasics.Error => IF reason.code = $Condition THEN { facing _ undetermined; CONTINUE; } ]; IF facing = back THEN back _ TRUE ELSE IF facing = front THEN front _ TRUE ELSE IF facing = undetermined THEN undetermined _ TRUE; ShapeUtilities.ReleasePatch[patch]; subdir[i*3 + j] _ facing; ENDLOOP; ENDLOOP; IF (back AND front) OR undetermined THEN p.dir _ undetermined ELSE IF back THEN p.dir _ back ELSE IF front THEN p.dir _ front ELSE p.dir _ undetermined; IF p.dir = undetermined THEN p.props _ PutPropSafely[p.props, $FacingDirArray, NEW[FacingDirArray _ subdir] ]; IF p.dir = back THEN RETURN[TRUE] ELSE RETURN[FALSE]; }; BezierPatchDivide: PROC[context: REF Context, p: REF Patch, midPt: MidPtProc] RETURNS[REF Patch, REF Patch, REF Patch, REF Patch] ~ { outPatch: ARRAY [0..4) OF REF Patch; row: ARRAY [0..8) OF REF VertexInfoSequence; col: ARRAY [0..4) OF REF VertexInfoSequence; IF Atom.GetPropFromList[p[ 0].props, $Straight] = $DoIt THEN SetStraight[ p, 0, 4, 8,12 ]; IF Atom.GetPropFromList[p[12].props, $Straight] = $DoIt THEN SetStraight[ p,12,13,14,15 ]; IF Atom.GetPropFromList[p[15].props, $Straight] = $DoIt THEN SetStraight[ p,15,11, 7, 3 ]; IF Atom.GetPropFromList[p[ 3].props, $Straight] = $DoIt THEN SetStraight[ p, 3, 2, 1, 0 ]; FOR i: NAT IN [0..4) DO p0, p1, p2, p3: REF VertexInfo; p0 _ CopyVtx[ p[i] ]; p1 _ CopyVtx[ p[i+4] ]; p2 _ CopyVtx[ p[i+8] ]; p3 _ CopyVtx[ p[i+12] ]; SELECT i FROM 0 => col[0] _ BezierCurveDivide[ p0, p1, p2, p3, midPt, front ]; -- p[0]-p[12], 0 leads 3 => col[3] _ BezierCurveDivide[ p0, p1, p2, p3, midPt, back ]; -- p[3]-p[15], 15 leads ENDCASE => col[i] _ BezierCurveDivide[ p0, p1, p2, p3, midPt, undetermined ]; ShapeUtilities.ReleaseVertexInfo[p0]; ShapeUtilities.ReleaseVertexInfo[p1]; ShapeUtilities.ReleaseVertexInfo[p2]; ShapeUtilities.ReleaseVertexInfo[p3]; ENDLOOP; FOR i: NAT IN [0..8) DO SELECT i FROM 0 => -- p[0] - p[3], 3 leads row[0] _ BezierCurveDivide[ col[0][0], col[1][0], col[2][0], col[3][0], midPt, back ]; 7 => -- p[12] - p[15], 12 leads row[7] _ BezierCurveDivide[ col[0][7], col[1][7], col[2][7], col[3][7], midPt, front ]; ENDCASE => row[i] _ BezierCurveDivide[ col[0][i], col[1][i], col[2][i], col[3][i], midPt, undetermined ]; ENDLOOP; FOR i: NAT IN [0..4) DO rowBase: NAT _ (i MOD 2) * 4; colBase: NAT _ (i / 2) * 4; outPatch[i] _ ShapeUtilities.GetPatch[16]; -- 16 point patch, released by display action outPatch[i].type _ p.type; outPatch[i].oneSided _ p.oneSided; outPatch[i].nVtces _ 16; outPatch[i].clipState _ p.clipState; outPatch[i].dir _ p.dir; outPatch[i].props _ p.props; FOR j: NAT IN [0..4) DO FOR k: NAT IN [0..4) DO outPatch[i][j*4 + k] _ row[colBase+j][rowBase+k]^; -- count along rows ENDLOOP; ENDLOOP; IF outPatch[i].clipState # in THEN { FOR j: NAT IN [0..16) DO OPEN outPatch[i][j].coord; clip _ ShapeUtilities.GetClipCodeForPt[ context, [ex, ey, ez] ]; IF clip = NoneOut THEN [ [sx, sy, sz] ] _ ShapeUtilities.XfmPtToDisplay[ context, [ex, ey, ez] ]; ENDLOOP; outPatch[i] _ BezierClipState[context, outPatch[i] ]; }; IF outPatch[i].dir = undetermined THEN [] _ BezierBackFacing[context, outPatch[i]]; ENDLOOP; FOR i: NAT IN [0..8) DO FOR j: NAT IN [0..row[i].length) DO -- return borrowed storage ShapeUtilities.ReleaseVertexInfo[ row[i][j] ]; ENDLOOP; ENDLOOP; FOR i: NAT IN [0..4) DO FOR j: NAT IN [0..col[i].length) DO ShapeUtilities.ReleaseVertexInfo[ col[i][j] ]; ENDLOOP; ENDLOOP; RETURN[ outPatch[0], outPatch[1], outPatch[2], outPatch[3] ]; -- return four sub-patches }; BezierCurveDivide: PROC[v0, v1, v2, v3: REF VertexInfo, midPt: MidPtProc, dir: FacingDir] RETURNS[pt: REF VertexInfoSequence] ~ { tempPt: REF VertexInfo; pt _ NEW[ VertexInfoSequence[8] ]; pt.length _ 8; pt[0] _ CopyVtx[ v0^ ]; pt[7] _ CopyVtx[ v3^ ]; -- preserve endpoints pt[1] _ midPt[v1, v0]; pt[6] _ midPt[v2, v3]; -- tangent midpoints tempPt _ midPt[v1, v2]; -- midway between inner knots pt[2] _ midPt[pt[1], tempPt]; pt[5] _ midPt[pt[6], tempPt]; -- midway between midpoints pt[3] _ midPt[pt[2], pt[5]]; -- midway between midways between midpoints pt[4] _ CopyVtx[ pt[3]^ ]; IF dir = front -- inner ends inherit outer props if on directed patch boundary THEN pt[4].props _ pt[0].props ELSE IF dir = back THEN pt[3].props _ pt[7].props; ShapeUtilities.ReleaseVertexInfo[ tempPt ]; }; BezierClipState: PatchProc ~ { ShapeUtilities.GetPatchClipState[ patch ]; IF patch.clipState = clipped THEN { FOR i: NAT IN [0..patch.nVtces) DO IF patch[i].coord.clip # NoneOut THEN { OPEN patch[i].coord; sx _ context.eyeToNdc.scaleX * ex / ez + context.eyeToNdc.addX; sy _ context.eyeToNdc.scaleY * ey / ez + context.eyeToNdc.addY; sz _ context.eyeToNdc.scaleZ / ez + context.eyeToNdc.addZ; IF sx < -0.5 OR sx > 1.5 OR sy < -0.5 OR sy > 1.5 OR sz < 0.0 THEN patch.clipState _ undetermined -- too far out for stability (arbitrary) ELSE { -- convert to screen coordinates sx _ context.ndcToPixels.scaleX * sx + context.ndcToPixels.addX; sy _ context.ndcToPixels.scaleY * sy + context.ndcToPixels.addY; sz _ context.ndcToPixels.scaleZ * sz + context.ndcToPixels.addZ; IF context.antiAliasing THEN { sx _ sx - 0.5; sy _ sy - 0.5; }; }; }; ENDLOOP; }; RETURN[patch]; }; BSplineDisplay: PatchProc ~ { RETURN[NIL]; }; BSplineDisplayLines: PatchProc ~ { RETURN[NIL]; }; NonConvexDisplay: PatchProc ~ { RETURN[NIL]; }; InitClasses[]; END. –StandardPatchProcs.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last Edited by: Crow, March 13, 1988 3:55:52 pm PST Internal Declarations Utility Procedures Difference f - g, returns zero if less than 6 decimal places Screen space f - g, returns zero if less than noticeable PROC[v0, v1: REF VertexInfo] RETURNS[REF VertexInfo] [[v.coord.sx, v.coord.sy, v.coord.sz]] _ ShapeUtilities.XfmPtToDisplay[ context, [v.coord.ex, v.coord.ey, v.coord.ez] ]; Find max distance from screen edge on inside Put property on new property list, to avoid clobbering other lists inherited from same place Remove property from new property list, to avoid clobbering lists inherited from same place Interpolate displayed values to point defined by projection of vMid on v1 - v0 Projection given by dot product normalized by magnitude of v1 - v0 Don't straighten eyespace coords, will cause shading discontinuities Straight! Force inner display values to lie on line between patch corners Length of control poly within tolerated deviation from linear All control point polygons touched by this edge face the same way Get screen distance of inner knots from edge formed by outer knots Get average of depths at corners PROC[context: REF Context, shape: REF ShapeInstance, data: REF] RETURNS[REF ShapeInstance]; Update shading and transform matrices) Transform vertices to eyespace, get clip state of vertices and whole shape Initialization of Classes Procedures for expansion of Bezier patches to convex polygons PROC[ context: REF Context, patch: REF Patch, data: REF ANY _ NIL ] RETURNS[REF Patch] Quit if out of field of view or all polys in convex hull point away from observer display in order [Artwork node; type 'Artwork on' to command tool] Quit if out of field of view or all polys in convex hull point away from observer Step from s=0 to s=1 if anti-aliasing else s=1 to s=0 PROC[ context: REF Context, patch: REF Patch, data: REF ANY _ NIL ] RETURNS[REF Patch] PROC[ context: REF Context, patch: REF Patch, data: REF ANY _ NIL ] RETURNS[REF Patch] Return patch corner vertices and calculate normal vectors Get normal at corner vertex,v, defined by cross-product of vectors formed by adjacent vertices. Vertices, nxtLft and nxtRgt are used in case of degenerate edges forming triangular patches Check that normal is not insignificantly small, if too small use outer knots only Get special output type for weird things like displacement mapping Polygons taken clockwise: Patches taken rowwise, right to left: [Artwork node; type 'Artwork on' to command tool] Check facing direction of each of the 9 polygons described by the 10 or 16 control points Subdivides a REF Patch for display purposes Expand patch by evaluating control point rows, to get 49 vertices Polygons taken clockwise: Patches taken rowwise, right to left: 3 -> 0 3 -> 0 3 2 1 0 ^ ^ 7 6 5 4 2 <- 1 15 <- 12 11 10 9 8 15 14 13 12 Have any edges been marked straight but not straightened? [p0, p1, p2, p3] => [col[0], col[1], col[2], col[3], col[4], col[5], col[6], col[7]] p0.props copied to col[0][0] and co[0]l[4], p3.props copied to col[3][7] and col[3][3] col[0], col[1], col[2], col[3] => row[0],row[1],row[2],row[3], row[4],row[5],row[6],row[7] col[0].props copied to row[0][0] & row[0][4], col[3].props copied to row[7][7] & row[7][3] outPatch[i][j*4 + k] _ CopyVtx[ row[colBase+j][rowBase+k]^ ]^; -- count along rows DeCasteljau subdivision algorithm PROC[ context: REF Context, patch: REF Patch, data: REF ANY _ NIL ] RETURNS[REF Patch] Procedures for expansion of B-Spline patches to convex polygons Procedure for expansion of Non-convex to semi-convex polygons Êz½˜Ihead™šœ Ïmœ1™ ˜[N˜=N˜=šžœžœžœ˜*J˜=N˜=N˜=N˜—šžœ žœ˜šžœ (˜1Mš œžœžœžœžœžœžœ˜BMšœžœ ˜Mš œžœžœžœ žœžœ˜=Mšœžœ ˜M˜—Mšžœ˜—J˜Jšžœ˜ J˜—š ¡ œžœžœžœžœ˜GJ˜I artworkFigure•GGFileæDGargoyle file for scene: stuffed from Gargoyle at February 27, 1988 4:02:09 pm PST Produced by version 8802.04 Scripts: Slope: [F 0.0] [F 30.0] [F 45.0] [F 60.0] [F 90.0] [F 120.0] [F 135.0] [F 150.0] Angle: [F -90.0] [F -60.0] [F -45.0] [F -30.0] [F 0.0] [F 30.0] [F 45.0] [F 60.0] [F 90.0] Radius: [F 4.0 4] [F 2.0 2] [F 1.0 1] [F 0.75 3/4] [F 0.6666667 2/3] [F 0.5 1/2] [F 0.3333333 1/3] [F 0.25 1/4] [F 0.125 1/8] [F 0.1111111 1/9] [F 5.555556e-2 1/18] LineDistance: [F 1.0 1] [F 0.5 1/2] [F 0.1111111 1/9] [F 5.555556e-2 1/18] [F 0.0 0] Midpoints: F Heuristics: F ShowAlignments: T ShowColors: F ScaleUnit: 72.0 DisplayStyle: print Gravity: T GravityExtent: 8.680555e-2 GravityType: pointsPreferred DefaultFont: xerox/pressfonts/helvetica-mrr [r1: 0.0 s: [10.0 10.0] r2: 0.0] 1.0 1.0 Defaults: [1 0.5] [1 1.0] 2.0 round round Dashed: F Shadows: []F Anchor: F Entities: [69]: Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [3] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [54.0,362.0] (Line ) [160.0,509.0] (Line ) [266.0,318.0] (Line ) [54.0,362.0] fwd: T Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [9] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [155.0,405.0] (Line ) [189.1274,456.5157] (Line ) [127.7821,464.3204] (Line ) [155.0,405.0] (Line ) [89.90349,411.7907] (Line ) [112.1553,349.93] (Line ) [155.0,405.0] (Line ) [185.7222,334.6614] (Line ) [232.5364,378.2977] (Line ) [155.0,405.0] fwd: T Text T "b" xerox/pressfonts/helvetica [10.0 0.0 271.0 0.0 10.0 311.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 241.0 0.0 10.0 378.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 199.0 0.0 10.0 458.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 167.0 0.0 10.0 513.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 105.0 0.0 10.0 469.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 64.0 0.0 10.0 416.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 29.0 0.0 10.0 363.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 95.0 0.0 10.0 340.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 168.0 0.0 10.0 326.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 167.0 0.0 10.0 409.0][] F 1.0 props: ( F ) Text T "003" xerox/pressfonts/helvetica [10.0 0.0 276.9375 0.0 10.0 306.2928][] F 1.0 props: ( F ) Text T "030" xerox/pressfonts/helvetica [10.0 0.0 172.9375 0.0 10.0 509.1609][] F 1.0 props: ( F ) Text T "300" xerox/pressfonts/helvetica [10.0 0.0 34.9375 0.0 10.0 358.2928][] F 1.0 props: ( F ) Text T "111" xerox/pressfonts/helvetica [10.0 0.0 172.9375 0.0 10.0 405.1609][] F 1.0 props: ( F ) Text T "021" xerox/pressfonts/helvetica [10.0 0.0 204.9375 0.0 10.0 453.2928][] F 1.0 props: ( F ) Text T "012" xerox/pressfonts/helvetica [10.0 0.0 246.9375 0.0 10.0 375.1609][] F 1.0 props: ( F ) Text T "210" xerox/pressfonts/helvetica [10.0 0.0 69.9375 0.0 10.0 413.1609][] F 1.0 props: ( F ) Text T "120" xerox/pressfonts/helvetica [10.0 0.0 110.9375 0.0 10.0 466.1609][] F 1.0 props: ( F ) Text T "201" xerox/pressfonts/helvetica [10.0 0.0 100.9375 0.0 10.0 336.1609][] F 1.0 props: ( F ) Text T "102" xerox/pressfonts/helvetica [10.0 0.0 173.9375 0.0 10.0 321.2928][] F 1.0 props: ( F ) Text T "0" xerox/pressfonts/Timesroman-B [12.0 0.0 266.0 0.0 12.0 326.8207][] F 1.0 props: ( F ) Text T "1" xerox/pressfonts/Timesroman-B [12.0 0.0 206.5 0.0 12.0 334.8207][] F 1.0 props: ( F ) Text T "2" xerox/pressfonts/Timesroman-B [12.0 0.0 124.5 0.0 12.0 349.8207][] F 1.0 props: ( F ) Text T "3" xerox/pressfonts/Timesroman-B [12.0 0.0 66.0 0.0 12.0 362.8207][] F 1.0 props: ( F ) Text T "4" xerox/pressfonts/Timesroman-B [12.0 0.0 101.0 0.0 12.0 414.8207][] F 1.0 props: ( F ) Text T "5" xerox/pressfonts/Timesroman-B [12.0 0.0 140.5 0.0 12.0 464.8207][] F 1.0 props: ( F ) Text T "6" xerox/pressfonts/Timesroman-B [12.0 0.0 143.5 0.0 12.0 506.8207][] F 1.0 props: ( F ) Text T "7" xerox/pressfonts/Timesroman-B [12.0 0.0 186.5 0.0 12.0 469.8207][] F 1.0 props: ( F ) Text T "8" xerox/pressfonts/Timesroman-B [12.0 0.0 229.5 0.0 12.0 393.8207][] F 1.0 props: ( F ) Text T "9" xerox/pressfonts/Timesroman-B [12.0 0.0 154.0 0.0 12.0 419.8207][] F 1.0 props: ( F ) Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [3] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [301.4636,373.7023] (Line ) [407.4636,520.7023] (Line ) [513.4636,329.7023] (Line ) [301.4636,373.7023] fwd: T Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [9] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [402.4636,416.7023] (Line ) [436.591,468.218] (Line ) [375.2457,476.0227] (Line ) [402.4636,416.7023] (Line ) [337.3671,423.493] (Line ) [359.6189,361.6323] (Line ) [402.4636,416.7023] (Line ) [433.1858,346.3637] (Line ) [480.0,390.0] (Line ) [402.4636,416.7023] fwd: T Outline fillColor: [1 0.0] ow: T Trajectories: [1] Traj (fence) [2] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [341.0,387.0] (Line ) [408.0,485.0] (Line ) [477.0,363.0] (Line ) fwd: T Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [3] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [376.2519,438.5625] (Line ) [405.5772,375.604] (Line ) [440.1239,428.2012] (Line ) [376.2519,438.5625] fwd: T Outline fillColor: [1 0.0] ow: T Trajectories: [1] Traj (fence) [2] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [379.0,402.0] (Line ) [409.0,454.0] (Line ) [441.0,391.0] (Line ) fwd: T Text T "0" xerox/pressfonts/Timesroman-B [12.0 0.0 477.0 0.0 12.0 367.5471][] F 1.0 props: ( F ) Text T "1" xerox/pressfonts/Timesroman-B [12.0 0.0 414.8247 0.0 12.0 378.0802][] F 1.0 props: ( F ) Text T "2" xerox/pressfonts/Timesroman-B [12.0 0.0 334.0 0.0 12.0 389.6848][] F 1.0 props: ( F ) Text T "3" xerox/pressfonts/Timesroman-B [12.0 0.0 370.0 0.0 12.0 440.6848][] F 1.0 props: ( F ) Text T "4" xerox/pressfonts/Timesroman-B [12.0 0.0 406.0 0.0 12.0 489.5471][] F 1.0 props: ( F ) Text T "5" xerox/pressfonts/Timesroman-B [12.0 0.0 441.0 0.0 12.0 429.6848][] F 1.0 props: ( F ) Text T "0" xerox/pressfonts/Timesroman-B [12.0 0.0 440.2183 0.0 12.0 398.181][] F 1.0 props: ( F ) Text T "1" xerox/pressfonts/Timesroman-B [12.0 0.0 373.0 0.0 12.0 407.5471][] F 1.0 props: ( F ) Text T "2" xerox/pressfonts/Timesroman-B [12.0 0.0 405.0 0.0 12.0 458.5471][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 469.0 0.0 10.0 354.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 388.0 0.0 10.0 371.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 324.0 0.0 10.0 382.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 344.3988 0.0 10.0 438.6395][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 409.6938 0.0 10.0 450.4688][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 447.0625 0.0 10.0 420.0][] F 1.0 props: ( F ) Text T "200" xerox/pressfonts/helvetica [10.0 0.0 329.9375 0.0 10.0 377.2928][] F 1.0 props: ( F ) Text T "101" xerox/pressfonts/helvetica [10.0 0.0 393.9375 0.0 10.0 366.2928][] F 1.0 props: ( F ) Text T "002" xerox/pressfonts/helvetica [10.0 0.0 474.9375 0.0 10.0 350.1609][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 435.0625 0.0 10.0 381.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 364.0 0.0 10.0 395.0][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 376.4296 0.0 10.0 485.8986][] F 1.0 props: ( F ) Text T "020" xerox/pressfonts/helvetica [10.0 0.0 382.3671 0.0 10.0 483.0595][] F 1.0 props: ( F ) Text T "110" xerox/pressfonts/helvetica [10.0 0.0 350.3363 0.0 10.0 433.9322][] F 1.0 props: ( F ) Text T "011" xerox/pressfonts/helvetica [10.0 0.0 453.0 0.0 10.0 415.2927][] F 1.0 props: ( F ) Text T "b" xerox/pressfonts/helvetica [10.0 0.0 401.3964 0.0 10.0 416.8291][] F 1.0 props: ( F ) Text T "001" xerox/pressfonts/helvetica [10.0 0.0 441.0 0.0 10.0 376.2928][] F 1.0 props: ( F ) Text T "100" xerox/pressfonts/helvetica [10.0 0.0 369.9375 0.0 10.0 391.1609][] F 1.0 props: ( F ) Text T "010" xerox/pressfonts/helvetica [10.0 0.0 415.6313 0.0 10.0 446.4688][] F 1.0 props: ( F ) Text T "000" xerox/pressfonts/helvetica [10.0 0.0 407.3339 0.0 10.0 412.1219][] F 1.0 props: ( F ) Text T "s=0" xerox/pressfonts/helvetica [10.0 0.0 383.69 0.0 10.0 340.1609][] F 1.0 props: ( F ) Text T "r=0" xerox/pressfonts/helvetica [10.0 0.0 458.315 0.0 10.0 443.1609][] F 1.0 props: ( F ) Text T "t=0" xerox/pressfonts/helvetica [10.0 0.0 326.6275 0.0 10.0 456.1609][] F 1.0 props: ( F ) –Ô83.15227 mm topLeading 83.15227 mm topIndent 1.411111 mm bottomLeading 0.5 0.3 0.95 backgroundColor the topLeading 6 pt .sub backgroundAscent 3 pt backgroundDescent 4 pt outlineBoxThickness 1 pt outlineBoxBearoff•Bounds:0.0 mm xmin 0.0 mm ymin 173.0247 mm xmax 80.33005 mm ymax •Artwork Interpress• InterpressÛ2Interpress/Xerox/3.0  f j k j¡¥“ļ= ¤ ¨ x j‡ÄÐ) ¢ ¨Ä¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨Ö ™@—ªÞ—Ö —˜ kÄ¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨;5™ÄK[fÄr!@—Ä&ïNÄyN—;5—Ä( rÄE++—ÄF‰¡Äˆ±d—;5—Ä ÄQ >—ÄcënÄEt/—;5—˜ k x jª ¤¯× ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤‘ ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤gj ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤G¡ ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤ u ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤à@ ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤½  ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤ÿô ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤Hæ ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤G9 ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤ÄOÄ1) ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á003– k x jª ¤Ä ÏÄ­ W ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á030– k x jª ¤Ä/Ä9b) ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á300– k x jª ¤Ä Ïĉ±W ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á111– k x jª ¤Ä ÏÄH™) ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á021– k x jª ¤ÄoÄW ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á012– k x jª ¤Ä_ÄŒiW ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á210– k x jª ¤ÄïÄžlW ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á120– k x jª ¤ÄOÄr>W ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á201– k x jª ¤Ä ßÄ3u) ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á102– k x j¬ ¤ªÄ‡Sj ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á0– k x j¬ ¤ÄÄŠ£j ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á1– k x j¬ ¤ÄùÄÙj ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á2– k x j¬ ¤âÄ–;j ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á3– k x j¬ ¤Ä«Ãj ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á4– k x j¬ ¤ÄÄFÐ' ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á5– k x j¬ ¤ÄÄM6' ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á6– k x j¬ ¤ÄuÄG“' ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á7– k x j¬ ¤ÄËÄ£j ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á8– k x j¬ ¤:Ä­Õj ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á9– kÄ¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨Ä‰nÄDœ/™ÄAB)Ä_™/—ÄR<)Äl/T—ĉnÄDœ/—˜ kÄ¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨Ä@u)ÄL/™Ä%…ÄŽ©N—ÄS9ÄQÑ,—Ä@u)ÄL/—ÄhOÄutG—įC3Ä`D—Ä@u)ÄL/—ÄvsFÄâ —€&—Ä@u)ÄL/—˜ k ¡¨õ#™8…—} —õ#—¡¡ ¡™ x j¢¯“¢°“¢·“¡¡¨õ#™8…—} —õ#—¡¸ kÄ¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨ÄÀ‰ƒÄi™ÄÂÞ{ÄFm0—ÄÂFqÄQ¤—ÄÀ‰ƒÄi—˜ k ¡¨2™9f—Y'—2—¡¡ ¡™ x j¢¯“¢°“¢·“¡¡¨2™9f—Y'—2—¡¸ k x j¬ ¤}ÄL5 ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á0– k x j¬ ¤Ä\]9Ä-» ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á1– k x j¬ ¤îÄoI ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á2– k x j¬ ¤Ä}ªI ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á3– k x j¬ ¤6ÄeZ5 ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á4– k x j¬ ¤YÄz‡I ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á5– k x j¬ ¤Ä^”7Ä£Qi ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á0– k x j¬ ¤ÄT`5 ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á1– k x j¬ ¤5Ä^ï5 ¢ ¥ ¨ÅxeroxÅ pressfontsÅTimesroman-brr£¡ “ •  —¡¡¨  Š¡²“Á2– k x jª ¤u ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤$ ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤ä ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤ÄÛI£Ä“[V ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤ÄNk1Ä8O  ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤ÄñD ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Áb– k x jª ¤ÄŸÄ˜DNšžœ< ˜Ušžœžœ˜šžœ 1˜=J˜9J˜9šžœ˜NšžœD˜H—šžœ˜NšžœD˜H—N˜9šžœžœ>˜DNšžœ:˜>NšžœE˜I—N˜—NšžœE˜I——Nšžœ˜N˜M™B—Mšœ žœžœ7˜PMšžœžœžœ˜5Nšœ ˜4šžœ˜šžœ˜N™BO–ÚInterpress/Xerox/3.0  f j k j¡¥“ļ= ¤ ¨ x jðÄÿpßW ¢ ¨Ä¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨Z˜™¼ŽÃT—aY—Z˜—˜ kÄ¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨›™ž—F—l–—r…—vn—rV—RŽ,[—X—v—þŠ—›—˜ kÄ¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨v™!x—\r—vn—˜ kÄ¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨r…™L‹——ÄŠ$eÄÀÆe—˜ kÄ¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨ž™—!x—,[—˜ kÄ¡¨ ¡ ¡™ x j¢¯“¢°“¢·“¡¡¨RV™\r—L‹—F—˜ k x jª ¤ûÄ’‡W ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á0– k x jª ¤(Q ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á1– k x jª ¤NÄ‘‚W ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á2– k x jª ¤vP ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á3– k x jª ¤öÄgW ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á4– k x jª ¤n ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á5– k x jª ¤õĤáW ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á8– k x jª ¤‚ ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á9– k x jª ¤A ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á10– k x jª ¤yƒ ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á11– k x jª ¤öž ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á12– k x jª ¤ÄÂa ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á13– k x jª ¤DÄÁËa ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á14– k x jª ¤ÄkÄ¿$a ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á15– k x jª ¤YÄ“ŒW ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á0– k x jª ¤TĬW ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á1– k x jª ¤¿Ä¿$a ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á2– k x jª ¤Ä“Ä‘‚W ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á3– k x jª ¤ÄëĬ“a ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á7– k x jª ¤Mh ¢ ¥ ¨ÅxeroxÅ pressfontsÅ helvetica-mrr£¡ “ •  —¡¡¨  Š¡²“Á6– k k k g– Interpress–:0.0 mm xmin 0.0 mm ymin 111.8306 mm xmax 37.49771 mm ymax –Ô40.31994 mm topLeading 40.31994 mm topIndent 1.411111 mm bottomLeading 0.5 0.3 0.95 backgroundColor the topLeading 6 pt .sub backgroundAscent 3 pt backgroundDescent 4 pt outlineBoxThickness 1 pt outlineBoxBearoff–"Gargoyle file for scene: stuffed from Gargoyle at February 27, 1988 3:45:46 pm PST Produced by version 8802.04 Scripts: ///Users/crow.pa/gargoyle/crow880227-15-04-33.script Slope: [F 0.0] [F 30.0] [F 45.0] [F 60.0] [F 90.0] [F 120.0] [F 135.0] [F 150.0] Angle: [F -90.0] [F -60.0] [F -45.0] [F -30.0] [F 0.0] [F 30.0] [F 45.0] [F 60.0] [F 90.0] Radius: [F 4.0 4] [F 2.0 2] [F 1.0 1] [F 0.75 3/4] [F 0.6666667 2/3] [F 0.5 1/2] [F 0.3333333 1/3] [F 0.25 1/4] [F 0.125 1/8] [F 0.1111111 1/9] [F 5.555556e-2 1/18] LineDistance: [F 1.0 1] [F 0.5 1/2] [F 0.1111111 1/9] [F 5.555556e-2 1/18] [F 0.0 0] Midpoints: F Heuristics: T ShowAlignments: F ShowColors: F ScaleUnit: 72.0 DisplayStyle: print Gravity: T GravityExtent: 8.680555e-2 GravityType: pointsPreferred DefaultFont: xerox/pressfonts/helvetica-mrr [r1: 0.0 s: [10.0 10.0] r2: 0.0] 1.0 1.0 Defaults: [1 0.5] [1 1.0] 2.0 round round Dashed: F Shadows: []F Anchor: F Entities: [26]: Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [4] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [186.0,504.0] (Line ) [284.0,504.0] (Line ) [291.0,436.0] (Line ) [193.0,441.0] (Line ) [186.0,504.0] fwd: T Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [12] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [352.0,507.0] (Line ) [383.0,510.0] (Line ) [422.0,509.0] (Line ) [460.0,502.0] (Line ) [466.0,485.0] (Line ) [470.0,462.0] (Line ) [466.0,438.0] (Line ) [434.0,438.0] (Line ) [396.0,443.0] (Line ) [353.0,440.0] (Line ) [352.0,470.0] (Line ) [350.0,490.0] (Line ) [352.0,507.0] fwd: T Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [3] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [352.0,470.0] (Line ) [385.0,472.0] (Line ) [444.0,466.0] (Line ) [470.0,462.0] fwd: T Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [3] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [466.0,485.0] (Line ) [428.0,491.0] (Line ) [376.0,493.0] (Line ) [350.1386,488.6139] fwd: T Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [3] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [383.0,510.0] (Line ) [376.0,493.0] (Line ) [385.0,472.0] (Line ) [396.0,443.0] fwd: T Outline fillColor: [1 0.5] ow: T Trajectories: [1] Traj (open) [3] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [434.0,438.0] (Line ) [444.0,466.0] (Line ) [428.0,491.0] (Line ) [422.0,509.0] fwd: T Text T "0" xerox/pressfonts/helvetica [10.0 0.0 347.0 0.0 10.0 431.1609][] F 1.0 props: ( F ) Text T "1" xerox/pressfonts/helvetica [10.0 0.0 392.0 0.0 10.0 433.0][] F 1.0 props: ( F ) Text T "2" xerox/pressfonts/helvetica [10.0 0.0 430.0 0.0 10.0 428.1609][] F 1.0 props: ( F ) Text T "3" xerox/pressfonts/helvetica [10.0 0.0 470.0 0.0 10.0 432.0][] F 1.0 props: ( F ) Text T "4" xerox/pressfonts/helvetica [10.0 0.0 342.0 0.0 10.0 463.1609][] F 1.0 props: ( F ) Text T "5" xerox/pressfonts/helvetica [10.0 0.0 379.0 0.0 10.0 462.0][] F 1.0 props: ( F ) Text T "8" xerox/pressfonts/helvetica [10.0 0.0 341.0 0.0 10.0 485.1609][] F 1.0 props: ( F ) Text T "9" xerox/pressfonts/helvetica [10.0 0.0 370.0 0.0 10.0 482.0][] F 1.0 props: ( F ) Text T "10" xerox/pressfonts/helvetica [10.0 0.0 417.0 0.0 10.0 481.0][] F 1.0 props: ( F ) Text T "11" xerox/pressfonts/helvetica [10.0 0.0 473.0 0.0 10.0 483.0][] F 1.0 props: ( F ) Text T "12" xerox/pressfonts/helvetica [10.0 0.0 342.0 0.0 10.0 510.0][] F 1.0 props: ( F ) Text T "13" xerox/pressfonts/helvetica [10.0 0.0 377.0 0.0 10.0 513.4536][] F 1.0 props: ( F ) Text T "14" xerox/pressfonts/helvetica [10.0 0.0 420.0 0.0 10.0 511.4536][] F 1.0 props: ( F ) Text T "15" xerox/pressfonts/helvetica [10.0 0.0 461.375 0.0 10.0 504.4536][] F 1.0 props: ( F ) Text T "0" xerox/pressfonts/helvetica [10.0 0.0 185.0 0.0 10.0 434.1609][] F 1.0 props: ( F ) Text T "1" xerox/pressfonts/helvetica [10.0 0.0 180.0 0.0 10.0 506.1609][] F 1.0 props: ( F ) Text T "2" xerox/pressfonts/helvetica [10.0 0.0 287.0 0.0 10.0 504.4536][] F 1.0 props: ( F ) Text T "3" xerox/pressfonts/helvetica [10.0 0.0 297.1875 0.0 10.0 428.1609][] F 1.0 props: ( F ) Text T "7" xerox/pressfonts/helvetica [10.0 0.0 477.375 0.0 10.0 455.4536][] F 1.0 props: ( F ) Text T "6" xerox/pressfonts/helvetica [10.0 0.0 429.0 0.0 10.0 456.0][] F 1.0 props: ( F ) š¡3™3NšœB ˜\NšœA ˜YNšœA ˜YN˜ANšœ %˜>N˜6N˜—šžœžœžœ 9˜VNšœ< ˜VNšœ< ˜TNšœ< ˜TNšœ  ˜9N˜4J˜——š žœžœžœžœ 6˜VšžœDžœ˜MNšœžœ žœ  0˜ON˜#N˜!N˜ šžœDžœ˜Lšžœž˜Nšž œ:˜E—Nšœ 9œ˜INšžœ˜ N˜—N˜—Nšžœ˜ —šžœ &˜>JšžœA˜E—Jšžœ˜ J˜—š ¡œžœ žœ žœ žœžœ˜PJ™YJ˜Jšœžœžœ˜+J˜Jšžœžœžœžœ˜$Jšžœžœžœžœ˜"šžœžœžœž˜šžœžœžœž˜Jšœžœ$˜.J˜šžœ˜šžœ˜Jšœžœ ˜1N˜BN˜—šžœžœžœ ˜3Jšœžœ˜ šžœž˜ JšœEžœ˜PJ˜HJšœEžœ˜PJšžœ˜—J˜——˜#Jšœžœ˜šœžœ˜5Jšžœžœ˜,—J˜—šžœžœž˜!šžœžœ ž˜(Jšžœžœžœ˜7——J˜#J˜Jšžœ˜—Jšžœ˜—šžœžœžœ˜$Jšžœ˜šžœžœ˜ Jšžœ˜šžœžœ˜Jšžœ˜Jšžœ˜———šžœžœ˜Jšœ2žœ˜Q—Jšžœžœžœžœžœžœžœ˜5J˜—š¡œžœ žœ žœ žœžœžœžœžœ ˜‹J™+Nšœ žœžœžœ˜$Nšœžœžœžœ˜,šœžœžœžœ˜,N™AN™BN™$N™N™$N™—N™9Jšžœ6žœ˜ZJšžœ6žœ˜ZJšžœ6žœ˜ZJšžœ6žœ˜Zšžœžœžœž˜Nšœžœ ˜N˜3N˜1N™XN™Wšžœž˜ NšœA ˜XNšœžœ; œ ˜XNšžœF˜M—N˜NN˜PNšžœ˜—šžœžœžœž˜N™\N™[šžœž˜ šœ )˜.N˜V—šœžœ ,˜2N˜W—šžœ ˜N˜U——Jšžœ˜—šžœžœžœž˜Jšœ žœžœ˜Jšœ žœžœ˜Jšœ+ -˜XN˜J˜"J˜J˜$J˜J˜šžœžœžœž˜šžœžœžœž˜Jšœ2 ˜FJšœ> ™RJšžœ˜—Jšžœ˜—šžœžœ˜$šžœžœžœ ž˜Jšžœ˜J˜@šžœ˜JšžœK˜O—Jšžœ˜—J˜5J˜—Nšžœ žœ-˜SJšžœ˜—šžœžœžœžœžœžœžœžœ ˜XN˜/Nšžœžœ˜—šžœžœžœžœžœžœžœž˜;N˜.Nšžœžœ˜—Jšžœ8 ˜XJšœŸ˜—š ¡œžœžœ/ž œžœ˜‡J™!Jšœžœ ˜Jšœžœ,˜4Jšœ3 ˜HJšœ1 ˜FJšœ  ˜=JšœB ˜ZJšœ% (˜MJ˜šžœ ?˜QJšžœ˜Jšžœžœ žœ˜2—J˜+Jšœ¡˜—š¡œ˜Mšžœ žœžœžœžœžœžœžœ™VJ˜*šžœžœ˜#šžœžœžœžœ˜#šžœžœ˜'Nšžœ˜N˜@N˜?N˜:š žœ žœ žœ žœ žœ ˜>Jšžœ! (˜Mšžœ   ˜0J˜@J˜@J˜@Jšžœžœ*˜FJ˜——J˜—Jšžœ˜—J˜—Jšžœ˜J˜——™?š¢œ˜Mšžœžœ˜ M˜—š¢œ˜"Mšžœžœ˜ M˜——™=š¢œ˜Mšžœžœ˜ M˜—M˜—˜J˜—Jšžœ˜—…——Œ ß