DIRECTORY Atom, Basics, BasicTime, Convert, G3dMatrix, G3dPlane, G3dRender, G3dScanConvert, G3dShadeClipXfm, G3dShape, G3dSortandDisplay, G3dVector, Real, Rope; G3dShadeClipXfmImpl: CEDAR MONITOR IMPORTS Atom, Basics, BasicTime, Convert, G3dMatrix, G3dPlane, G3dRender, G3dVector, Real, Rope EXPORTS G3dShadeClipXfm ~ BEGIN Context: TYPE ~ G3dRender.Context; RGB: TYPE ~ G3dRender.RGB; -- [ r, g, b: REAL]; SixSides: TYPE ~ G3dRender.SixSides; ScaleAndAddXfm: TYPE ~ G3dRender.ScaleAndAddXfm; OutCode: TYPE ~ G3dRender.OutCode; Matrix: TYPE ~ G3dRender.Matrix; Triple: TYPE ~ G3dRender.Triple; TripleSequence: TYPE ~ G3dRender.TripleSequence; NatSequence: TYPE ~ G3dRender.NatSequence; IntegerSequence: TYPE ~ G3dRender.IntegerSequence; RealSequence: TYPE ~ G3dRender.RealSequence; Shape: TYPE ~ G3dRender.Shape; FacingDir: TYPE ~ G3dRender.FacingDir; Patch: TYPE ~ G3dRender.Patch; VertexSequence: TYPE ~ G3dShape.VertexSequence; PatchSequence: TYPE ~ G3dRender.PatchSequence; PatchSequenceRep: TYPE ~ G3dRender.PatchSequenceRep; CtlPoint: TYPE ~ G3dRender.CtlPoint; CtlPointSequence: TYPE ~ G3dRender.CtlPointSequence; CtlPtInfo: TYPE ~ G3dRender.CtlPtInfo; CtlPtInfoSequence: TYPE ~ G3dRender.CtlPtInfoSequence; CtlPtInfoSequenceRep: TYPE ~ G3dRender.CtlPtInfoSequenceRep; CtlPtInfoProc: TYPE ~ G3dRender.CtlPtInfoProc; Shading: TYPE ~ G3dRender.Shading; ShadingSequence: TYPE ~ G3dRender.ShadingSequence; ShapeClass: TYPE ~ G3dRender.ShapeClass; ShadingClass: TYPE ~ G3dRender.ShadingClass; ShapeProc: TYPE ~ G3dRender.ShapeProc; -- PROC[ Context, Shape ] LORA: TYPE ~ LIST OF REF ANY; NoneOut: OutCode ~ G3dRender.NoneOut; AllOut: OutCode ~ G3dRender.AllOut; Transform: PROC[p: Triple, mat: Matrix] RETURNS[Triple] ~ G3dMatrix.Transform; TransformVec: PROC[vec: Triple, mat: Matrix] RETURNS[Triple] ~ G3dMatrix.TransformVec; 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; nullPtr: INT ~ 0; -- handy name for zero in sort sequences nullTriple: Triple _ [0.0, 0.0, 0.0]; vertexStore: CtlPtInfoSequence _ NEW[ CtlPtInfoSequenceRep[96] ]; -- CtlPoint Cache vertexStoreLength: NAT _ 96; vertexStorePtr: NAT _ 0; -- place to return next free record GetCtlPtInfo: PUBLIC ENTRY PROC[] RETURNS[REF CtlPtInfo] ~ { ENABLE UNWIND => NULL; vtx: REF CtlPtInfo; IF vertexStorePtr = 0 THEN vtx _ NEW[CtlPtInfo] ELSE { vertexStorePtr _ vertexStorePtr - 1; vtx _ vertexStore[vertexStorePtr]; vertexStore[vertexStorePtr] _ NIL; }; RETURN[ vtx ]; }; ReleaseCtlPtInfo: PUBLIC ENTRY PROC[vtx: REF CtlPtInfo] ~ { ENABLE UNWIND => NULL; IF vertexStorePtr = vertexStoreLength THEN { vertexStore _ NEW[ CtlPtInfoSequenceRep[vertexStoreLength + 32] ]; vertexStoreLength _ vertexStoreLength + 32; vertexStorePtr _ 0; }; IF vertexStorePtr > 0 AND vertexStore[vertexStorePtr-1] = vtx THEN SIGNAL G3dRender.Error[$MisMatch, "Double vertexInfo release"] ELSE vertexStore[vertexStorePtr] _ vtx; vertexStorePtr _ vertexStorePtr + 1; }; patchCache: PatchSequence _ NEW[ PatchSequenceRep[16] ]; -- temps for clipping, etc. patchCacheLength: NAT _ 16; patchCachePtr: NAT _ 0; -- place to return next free record GetPatch: PUBLIC ENTRY PROC[size: NAT] RETURNS[REF Patch] ~ { ENABLE UNWIND => NULL; p: REF Patch; IF patchCachePtr = 0 THEN p _ NEW[Patch[size]] ELSE { patchCachePtr _ patchCachePtr - 1; p _ patchCache[patchCachePtr]; patchCache[patchCachePtr] _ NIL; IF p.maxLength < size THEN p _ NEW[Patch[size]]; }; RETURN[ p ]; }; ReleasePatch: PUBLIC ENTRY PROC[p: REF Patch] ~ { ENABLE UNWIND => NULL; IF p = NIL THEN RETURN[]; IF patchCachePtr = patchCacheLength THEN { patchCache _ NEW[ PatchSequenceRep[patchCacheLength + 2] ]; patchCacheLength _ patchCacheLength + 2; patchCachePtr _ 0; }; IF patchCachePtr > 0 AND patchCache[patchCachePtr-1] = p THEN SIGNAL G3dRender.Error[$MisMatch, "Double patch release"] ELSE patchCache[patchCachePtr] _ p; patchCachePtr _ patchCachePtr + 1; }; Sgn: PROCEDURE [number: REAL] RETURNS [INT] ~ INLINE { IF number < 0. THEN RETURN[-1] ELSE RETURN[1]; }; Ceiling: PROC[number: REAL] RETURNS[result: INTEGER] ~ { result _ Real.Round[number]; IF result < number THEN result _ result + 1; }; ElapsedTime: PROC[startTime: REAL] RETURNS[Rope.ROPE] ~ { timeX10: REAL _ 10.0 * (BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]] - startTime); RETURN[ Rope.Cat[ Convert.RopeFromReal[ Real.Fix[timeX10] / 10.0 ], " secs. " ] ]; }; CurrentTime: PROC[] RETURNS[REAL] ~ { RETURN[ BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]] ]; }; DiffPosns: PROC[vtx1, vtx2: CtlPoint] RETURNS[Triple] ~ { RETURN[[vtx1.x - vtx2.x, vtx1.y - vtx2.y, vtx1.z - vtx2.z]] }; GetNormal: PROC[ vertices: VertexSequence, poly: NatSequence, cVtx: NAT ] RETURNS[ normal: Triple ] ~ { lVtx: NAT _ poly[ (cVtx + poly.length - 1) MOD poly.length ]; nVtx: NAT _ poly[ (cVtx + 1) MOD poly.length ]; cVtx _ poly[cVtx]; normal _ G3dVector.Cross[ -- in object space so do right-handed G3dVector.Sub[ vertices[lVtx].point, vertices[cVtx].point ], G3dVector.Sub[ vertices[nVtx].point, vertices[cVtx].point ] ]; }; HoldEverything: PROCEDURE [] ~ { ERROR ABORTED; }; GetPolyNmls: PUBLIC PROC[context: Context, shape: Shape] ~ { xfm: Matrix _ G3dMatrix.Mul[shape.matrix, context.eyeSpaceXfm]; IF shape.faces.valid.normal THEN RETURN; -- don't mess with pre-existing normals IF shape.type # $ConvexPolygon AND shape.type # $Poly THEN { SIGNAL G3dRender.Error[$MisMatch, "Operation only for polygons"]; RETURN[]; }; FOR i: NAT IN [0..shape.surfaces.length) DO sumNmls: Triple _ [0., 0., 0.]; FOR cVtx: NAT IN [0..shape.surfaces[i].length) DO sumNmls _ G3dVector.Add[ sumNmls, GetNormal[shape.vertices, shape.surfaces[i], cVtx] ]; ENDLOOP; shape.faces[i].normal _ G3dVector.Normalize[sumNmls]; ENDLOOP; shape.faces.valid.normal _ TRUE; }; GetVtxNmls: PUBLIC PROC[context: Context, shape: Shape] ~ { xfm: Matrix _ G3dMatrix.Mul[shape.matrix, context.eyeSpaceXfm]; IF shape.vertices.valid.normal THEN RETURN; -- don't mess with pre-existing normals IF shape.type # $ConvexPolygon AND shape.type # $Poly THEN { SIGNAL G3dRender.Error[$MisMatch, "Operation only for polygons"]; RETURN[]; }; FOR i: NAT IN [0..shape.surfaces.length) DO -- get normals at vertices, add to earlier ones IF shape.surfaces[i] # NIL THEN FOR cVtx: NAT IN [0..shape.surfaces[i].length) DO OPEN shape.vertices[shape.surfaces[i][cVtx]]; cornerNormal: Triple _ GetNormal[ shape.vertices, shape.surfaces[i], cVtx ]; normal _ G3dVector.Add[ cornerNormal, normal]; -- assumes normal initally zero ENDLOOP; ENDLOOP; FOR i: NAT IN [0..shape.vertices.length) DO IF shape.vertices[i] # NIL THEN { OPEN shape.vertices[i]; IF G3dVector.Length[ normal ] > shape.sphereExtent.radius * .0001 THEN normal _ G3dVector.Normalize[ normal ] ELSE normal _ nullTriple; }; ENDLOOP; shape.vertices.valid.normal _ TRUE; }; ClipBoundingSphere: PUBLIC PROC[context: Context, shape: Shape, xfm: Matrix] RETURNS[G3dRender.ClipState] ~ { clipFlag: BOOLEAN _ FALSE; center: Triple _ shape.sphereExtent.center; eyeCtr: Triple _ G3dMatrix.Transform[ center, xfm]; FOR plane: SixSides IN SixSides DO distance: REAL _ G3dPlane.DistanceToPoint[ eyeCtr, context.clippingPlanes[plane] ]; IF distance < -shape.sphereExtent.radius THEN RETURN[out] ELSE IF distance < shape.sphereExtent.radius THEN clipFlag _ TRUE; ENDLOOP; IF clipFlag THEN RETURN[clipped] ELSE RETURN[in]; }; ClipPoly: PUBLIC PROC[ context: Context, poly: REF Patch] RETURNS [REF Patch] ~ { Clip: PROC[side: SixSides, pIn, pOut: REF Patch] RETURNS [REF Patch, REF Patch] = { Dist: PROC[side: SixSides, vtx: CtlPoint] RETURNS [REAL] = { -- + inside, - outside RETURN[ G3dPlane.DistanceToPoint[ [vtx.ex, vtx.ey, vtx.ez], context.clippingPlanes[side] ] ]; }; lastDist, dist: REAL; outCnt, last: NAT; IF pIn.nVtces < 2 THEN RETURN[ pIn, pOut ]; -- return if degenerate (line needs 2) outCnt _ 0; IF pIn.type # $PolyLine THEN { lastDist _ Dist[side, pIn.ctlPt[pIn.nVtces - 1].coord]; last _ pIn.nVtces - 1; }; IF pOut.maxLength < 2 * pIn.nVtces THEN pOut _ NEW[Patch[2 * pIn.nVtces]]; FOR i: NAT IN [0..pIn.nVtces) DO a, b: REAL; dist _ Dist[side, pIn.ctlPt[i].coord]; IF (i # 0 OR pIn.type # $PolyLine) AND lastDist * dist < 0. THEN { b _ dist / (dist - lastDist); a _ 1.0 - b; pOut.ctlPt[outCnt].coord.x _ pIn.ctlPt[i].coord.x * a + pIn.ctlPt[last].coord.x * b; pOut.ctlPt[outCnt].coord.y _ pIn.ctlPt[i].coord.y * a + pIn.ctlPt[last].coord.y * b; pOut.ctlPt[outCnt].coord.z _ pIn.ctlPt[i].coord.z * a + pIn.ctlPt[last].coord.z * b; pOut.ctlPt[outCnt].coord.ex _ pIn.ctlPt[i].coord.ex * a + pIn.ctlPt[last].coord.ex * b; pOut.ctlPt[outCnt].coord.ey _ pIn.ctlPt[i].coord.ey * a + pIn.ctlPt[last].coord.ey * b; pOut.ctlPt[outCnt].coord.ez _ pIn.ctlPt[i].coord.ez * a + pIn.ctlPt[last].coord.ez * b; pOut.ctlPt[outCnt].shade.exn _ pIn.ctlPt[i].shade.exn*a + pIn.ctlPt[last].shade.exn*b; pOut.ctlPt[outCnt].shade.eyn _ pIn.ctlPt[i].shade.eyn*a + pIn.ctlPt[last].shade.eyn*b; pOut.ctlPt[outCnt].shade.ezn _ pIn.ctlPt[i].shade.ezn*a + pIn.ctlPt[last].shade.ezn*b; pOut.ctlPt[outCnt].shade.r _ pIn.ctlPt[i].shade.r * a + pIn.ctlPt[last].shade.r * b; pOut.ctlPt[outCnt].shade.g _ pIn.ctlPt[i].shade.g * a + pIn.ctlPt[last].shade.g * b; pOut.ctlPt[outCnt].shade.b _ pIn.ctlPt[i].shade.b * a + pIn.ctlPt[last].shade.b * b; pOut.ctlPt[outCnt].shade.t _ pIn.ctlPt[i].shade.t * a + pIn.ctlPt[last].shade.t* b; pOut.ctlPt[outCnt].shade.txtrX _ pIn.ctlPt[i].shade.txtrX * a + pIn.ctlPt[last].shade.txtrX* b; pOut.ctlPt[outCnt].shade.txtrY _ pIn.ctlPt[i].shade.txtrY * a + pIn.ctlPt[last].shade.txtrY* b; pOut.ctlPt[outCnt].shade.er _ pIn.ctlPt[i].shade.er * a + pIn.ctlPt[last].shade.er * b; pOut.ctlPt[outCnt].shade.eg _ pIn.ctlPt[i].shade.eg * a + pIn.ctlPt[last].shade.eg * b; pOut.ctlPt[outCnt].shade.eb _ pIn.ctlPt[i].shade.eb * a + pIn.ctlPt[last].shade.eb * b; pOut.ctlPt[outCnt].shade.et _ pIn.ctlPt[i].shade.et * a + pIn.ctlPt[last].shade.et * b; outCnt _ outCnt + 1; }; IF dist >= 0. THEN { -- put out point if inside pOut.ctlPt[outCnt].coord.x _ pIn.ctlPt[i].coord.x; pOut.ctlPt[outCnt].coord.y _ pIn.ctlPt[i].coord.y; pOut.ctlPt[outCnt].coord.z _ pIn.ctlPt[i].coord.z; pOut.ctlPt[outCnt].coord.ex _ pIn.ctlPt[i].coord.ex; pOut.ctlPt[outCnt].coord.ey _ pIn.ctlPt[i].coord.ey; pOut.ctlPt[outCnt].coord.ez _ pIn.ctlPt[i].coord.ez; pOut.ctlPt[outCnt].shade.exn _ pIn.ctlPt[i].shade.exn; pOut.ctlPt[outCnt].shade.eyn _ pIn.ctlPt[i].shade.eyn; pOut.ctlPt[outCnt].shade.ezn _ pIn.ctlPt[i].shade.ezn; pOut.ctlPt[outCnt].shade.r _ pIn.ctlPt[i].shade.r; pOut.ctlPt[outCnt].shade.g _ pIn.ctlPt[i].shade.g; pOut.ctlPt[outCnt].shade.b _ pIn.ctlPt[i].shade.b; pOut.ctlPt[outCnt].shade.t _ pIn.ctlPt[i].shade.t; pOut.ctlPt[outCnt].shade.txtrX _ pIn.ctlPt[i].shade.txtrX; pOut.ctlPt[outCnt].shade.txtrY _ pIn.ctlPt[i].shade.txtrY; pOut.ctlPt[outCnt].shade.er _ pIn.ctlPt[i].shade.er; pOut.ctlPt[outCnt].shade.eg _ pIn.ctlPt[i].shade.eg; pOut.ctlPt[outCnt].shade.eb _ pIn.ctlPt[i].shade.eb; pOut.ctlPt[outCnt].shade.et _ pIn.ctlPt[i].shade.et; outCnt _ outCnt + 1; }; lastDist _ dist; last _ i; ENDLOOP; pOut.type _ pIn.type; pOut.oneSided _ pIn.oneSided; pOut.dir _ pIn.dir; pOut.nVtces _ outCnt; pOut.renderData _ pIn.renderData; pOut.props _ pIn.props; RETURN [ pOut, pIn ]; }; -- end Clip Proc orOfCodes: OutCode _ NoneOut; poly2: REF Patch _ GetPatch[2 * poly.nVtces]; -- get temp patch, released below IF poly.type # $ConvexPolygon AND poly.type # $Poly AND poly.type # $PolyLine THEN { SIGNAL G3dRender.Error[$Unimplemented, "Not clippable as polygon"]; RETURN[ NIL ]; }; FOR i: NAT IN [0..poly.nVtces) DO orOfCodes _ LOOPHOLE[ Basics.BITOR[LOOPHOLE[orOfCodes], LOOPHOLE[poly.ctlPt[i].coord.clip]], OutCode]; ENDLOOP; IF orOfCodes.near THEN [poly, poly2] _ Clip[ Near, poly, poly2]; IF orOfCodes.far THEN [poly, poly2] _ Clip[ Far, poly, poly2]; IF orOfCodes.left THEN [poly, poly2] _ Clip[ Left, poly, poly2]; IF orOfCodes.right THEN [poly, poly2] _ Clip[ Right, poly, poly2]; IF orOfCodes.bottom THEN [poly, poly2] _ Clip[Bottom, poly, poly2]; IF orOfCodes.top THEN [poly, poly2] _ Clip[ Top, poly, poly2]; ReleasePatch[poly2]; -- done with temp patch RETURN[ poly ]; }; GetPatchClipState: PUBLIC PROC[ patch: REF Patch] ~ { orOfCodes: OutCode _ NoneOut; andOfCodes: OutCode _ AllOut; FOR i: NAT IN [0..patch.nVtces) DO orOfCodes _ LOOPHOLE[ Basics.BITOR[ LOOPHOLE[orOfCodes], LOOPHOLE[patch[i].coord.clip]], OutCode]; andOfCodes _ LOOPHOLE[ Basics.BITAND[LOOPHOLE[andOfCodes], LOOPHOLE[patch[i].coord.clip]], OutCode]; ENDLOOP; IF andOfCodes # NoneOut THEN patch.clipState _ out ELSE IF orOfCodes = NoneOut THEN patch.clipState _ in ELSE patch.clipState _ clipped; }; GetClipCodeForPt: PUBLIC PROC[context: Context, pt: Triple] RETURNS[clip: OutCode] ~ { clip.bottom_ G3dPlane.DistanceToPoint[ pt, context.clippingPlanes[Bottom]] < 0.; clip.top _ G3dPlane.DistanceToPoint[ pt, context.clippingPlanes[Top] ] < 0.; clip.left _ G3dPlane.DistanceToPoint[ pt, context.clippingPlanes[Left] ] < 0.; clip.right _ G3dPlane.DistanceToPoint[ pt, context.clippingPlanes[Right] ] < 0.; clip.near _ G3dPlane.DistanceToPoint[ pt, context.clippingPlanes[Near] ] < 0.; clip.far _ G3dPlane.DistanceToPoint[ pt, context.clippingPlanes[Far] ] < 0.; }; XfmPtToEyeSpace: PUBLIC PROC[context: Context, pt: Triple, xfm: Matrix _ NIL] RETURNS[Triple, OutCode] ~ { IF xfm = NIL THEN xfm _ context.eyeSpaceXfm; pt _ Transform[ pt, xfm ]; RETURN[ pt, GetClipCodeForPt[context, pt] ]; }; XfmTripleToDisplay: PUBLIC PROC[pt: Triple, xfm, display: ScaleAndAddXfm, offset: REAL] RETURNS[result: Triple] ~ { aLilBit: REAL _ G3dScanConvert.justNoticeable * G3dScanConvert.justNoticeable; IF pt.z <= 0.0 THEN { SIGNAL G3dRender.Error[$MisMatch, "Negative depth"]; pt.z _ .001; -- fudge bad depths }; result.x _ xfm.scaleX*pt.x/pt.z + xfm.addX; -- convert to normalized display coords result.y _ xfm.scaleY*pt.y/pt.z + xfm.addY; result.z _ xfm.scaleZ/pt.z + xfm.addZ; result.x _ display.scaleX * result.x + display.addX; -- convert to screen coordinates result.y _ display.scaleY * result.y + display.addY; result.z _ display.scaleZ * result.z + display.addZ; result.x _ result.x - offset; -- nojaggy tiler offsets by 1/2 pixel and spreads out by 1 result.y _ result.y - offset; RETURN [ result ]; }; XfmPtToDisplay: PUBLIC PROC[context: Context, pt: Triple, shape: Shape _ NIL] RETURNS[Triple] ~ { result: Triple _ XfmTripleToDisplay[ pt: pt, xfm: context.eyeToNdc, display: context.ndcToPixels, offset: IF context.antiAliasing THEN .5 ELSE 0.0 -- nojaggy tiler offsets by 1/2 pixel ]; IF shape # NIL THEN { xLo: INTEGER _ Real.Fix[ MAX[0.0, result.x - 2.0] ]; xHi: INTEGER _ Ceiling[ MIN[context.viewPort.w, result.x + 2.0] ]; yLo: INTEGER _ Real.Fix[ MAX[0.0, result.y - 2.0] ]; yHi: INTEGER _ Ceiling[ MIN[context.viewPort.h, result.y + 2.0] ]; IF shape.screenExtent.min.x > xLo THEN shape.screenExtent.min.x _ xLo; IF shape.screenExtent.max.x < xHi THEN shape.screenExtent.max.x _ xHi; IF shape.screenExtent.min.y > yLo THEN shape.screenExtent.min.y _ yLo; IF shape.screenExtent.max.y < yHi THEN shape.screenExtent.max.y _ yHi; }; RETURN [ result ]; }; BackFacing: PUBLIC PROC[ context: Context, poly: REF Patch, useEyeSpace: BOOLEAN _ FALSE ] RETURNS [FacingDir] ~ { SELECT poly.type FROM $ConvexPolygon, $Poly => IF useEyeSpace THEN { this: CtlPtInfo _ poly.ctlPt[0]; next: CtlPtInfo _ poly.ctlPt[1]; last: CtlPtInfo _ poly.ctlPt[2]; direction: Triple _ G3dVector.Normalize[G3dVector.Cross[ [next.coord.ex - this.coord.ex, next.coord.ey - this.coord.ey, next.coord.ez - this.coord.ez], [last.coord.ex - this.coord.ex, last.coord.ey - this.coord.ey, last.coord.ez - this.coord.ez] ] ]; dotDir: REAL _ G3dVector.Dot[[this.coord.ex, this.coord.ey, this.coord.ez] , direction]; IF dotDir > 0.0 THEN RETURN[back] ELSE IF dotDir < 0.0 THEN RETURN[front]; } ELSE { -- do check in image space, rejecting eensy polygon edges s: REAL _ 1.0 / G3dScanConvert.justNoticeable; -- scales visible feature size to 1 FOR i: NAT IN [0..poly.nVtces) DO this: CtlPtInfo _ poly.ctlPt[i]; next: CtlPtInfo _ poly.ctlPt[(i+1) MOD poly.nVtces]; last: CtlPtInfo _ poly.ctlPt[(i+poly.nVtces-1) MOD poly.nVtces]; zNorm: INT _ -- integer computation of z-coord of normal (left-handed) ( Real.Fix[s*next.coord.sx - s*this.coord.sx] ) * ( Real.Fix[s*last.coord.sy - s*this.coord.sy] ) - ( Real.Fix[s*next.coord.sy - s*this.coord.sy] ) * ( Real.Fix[s*last.coord.sx - s*this.coord.sx] ); zNorm _ zNorm *Sgn[context.ndcToPixels.scaleY] *Sgn[context.ndcToPixels.scaleX]; IF zNorm > 0 THEN RETURN[ back ] ELSE IF zNorm < 0 THEN RETURN[ front ]; ENDLOOP; SIGNAL G3dRender.Error[$Condition, "Edges too small for stable arithmetic"]; }; $Bezier => { SIGNAL G3dRender.Error[$Unimplemented, "Backfacing for patches not done"]; }; ENDCASE => SIGNAL G3dRender.Error[$Unimplemented, "Unknown type"]; RETURN[ unknown ]; }; ShadePoly: PUBLIC PROC[ context: Context, poly: REF Patch] ~ { IF poly.renderData.shadingClass.renderMethod # $HiddenLines THEN FOR i: NAT IN [0..poly.nVtces) DO IF poly.renderData.shadingClass.renderMethod = $Faceted THEN { -- nmls from vtx coords lVtx: NAT _ (i + poly.nVtces - 1) MOD poly.nVtces; nVtx: NAT _ (i + 1) MOD poly.nVtces; [[ poly[i].shade.exn, poly[i].shade.eyn, poly[i].shade.ezn ]] _ G3dVector.Cross[ [ poly[nVtx].coord.ex - poly[i].coord.ex, -- in eyespace, so do left-handed poly[nVtx].coord.ey - poly[i].coord.ey, poly[nVtx].coord.ez - poly[i].coord.ez ], [ poly[lVtx].coord.ex - poly[i].coord.ex, poly[lVtx].coord.ey - poly[i].coord.ey, poly[lVtx].coord.ez - poly[i].coord.ez ] ]; }; poly[i] _ poly.renderData.shadingClass.shadeVtx[ context, poly[i], poly.renderData.shadingClass ]; ENDLOOP; }; END.  G3dShadeClipXfmImpl.mesa Copyright c 1984, 1986 by Xerox Corporation. All rights reserved. Last Edited by: Crow, May 16, 1989 2:57:15 pm PDT Internal Declarations Renamed Procedures Global Variables Caching Procedures allocation avoidance structures - caches of peculiar data types Utility Procedures Procedures for Manipulating Shapes Compute Normals, Sum normals at polygon corners to get polygon normal Sum normals for vertices given by adjacent polygon corners, only for polygons! Sum normals for vertices given by adjacent polygon corners, only for polygons! Procedures for Transformations and Clipping Do gross clip test on bounding sphere, all in or all out can avoid clipping entire object Put out point if clip plane crossed Compute outcode for one set of coordinates in eyespace Transform CtlPoint to Eye Space Transform vertex from eyespace to display coordinates - local utility Transform vertex from eyespace to display coordinates Procedures for Shading Patches Assumes left-handed space (eye space or screen space) Backfacing test based on first vertex and adjacent vertices last: CtlPtInfo _ poly.ctlPt[poly.nVtces - 1]; Adjusts for flip in screen-space transform (ndcToPixels) in y and/or x Backfacing test based on convex hull being hidden behind its base Κ˜J™šœ Οmœ7™BJšœ1™1J˜JšΟk œ—˜ J˜—head2šΡblnΠln ŸΠblΡbkl‘’Πkl˜"IašžœX˜_Lšžœ˜J˜Jšœžœ˜J˜—headšΟl™Jšœ žœ˜%Jšžœžœ žœΟc˜9Jšœ žœ˜'Jšœžœ˜0Jšœ žœ˜%Jšœ žœ˜#Jšœ žœ˜#Jšœžœ˜1Jšœžœ˜,Jšœžœ˜3Jšœžœ˜-Jšœ žœ˜"Jšœ žœ˜(Jšœ žœ˜"Jšœžœ˜0Jšœžœ˜/Jšœžœ˜4Jšœ žœ˜'Jšœžœ˜4Jšœžœ˜)Jšœžœ˜6Jšœžœ"˜Jšžœžœžœ˜Nšœžœ˜ šžœ˜Nšžœžœ ˜šžœ˜N˜"N˜Nšœžœ˜ Nšžœžœžœ˜2N˜——Nšžœ˜ N˜—š ¦ œžœžœžœžœ ˜1Jšžœžœžœ˜Nšžœžœžœžœ˜šžœ"žœ˜*Nšœ žœ+˜;N˜(N˜N˜—šžœžœ!˜9Nšžœžœ3˜>Nšžœ˜#—N˜"N˜——š€™š ¦œž œ žœžœžœžœ˜7Lš žœ žœžœžœžœ˜1L˜L˜—š ¦œžœ žœžœ žœ˜8J˜Jšžœžœ˜,J˜—š ¦ œžœ žœžœžœ˜:Jšœ žœN˜[JšžœL˜RJ˜—š¦ œžœžœžœ˜&Jšžœ:˜@Jšœ˜—š¦ œžœžœ ˜9Jšžœ8˜>J˜—š¦ œžœ5žœž œ˜nJšœžœ"žœ˜>Jšœžœžœ˜/Jšœ˜šœ ₯%˜EJšœ<˜š žœ8ž œžœžœž˜bšžœ6žœ₯˜VJšœžœžœ˜3Jšœžœ žœ ˜$˜Pšœ.₯!˜OJ˜(J˜*—˜+J˜(J˜)—J˜—L˜—šœ1˜1Lšœ/˜/Lšœ˜—Lšžœ˜—L˜L™——Jšžœ˜—…—FΤ\θ