TnsrTriangleDivide: 
PROC[ context: Context, p: 
REF Patch, tol: 
REAL] ~ {
Divide triangular patch into three subquadrilaterals and send to display
shape: Shape ← NARROW[ GetProp[p.props, $Shape] ];
v0, v1, v2, vCtr, vCtr1, vCtr2, vCtr3: CtlPtInfo;  flat0, flat1, flat2: BOOLEAN;
t: REF TangentTriple ← NARROW[GetProp[p.props, $Tangents] ];
t00, t01, t10, t11, t20, t21, tm0, tm1, tm2: TangentSet;
outPatch: PatchSequence ← NEW[PatchSequenceRep[3]];
Find midpoints and midslopes for each side
[v0, t00, t01, flat0] ← CurveDivideTan[ 
context, p[0], p[1], t[0].et0, t[0].et1, 
GetNmlVec[t[0].et0, p[0]], GetNmlVec[t[0].et1, p[1], TRUE], 0.5, tol ];
[v1, t10, t11, flat1] ← CurveDivideTan[
context, p[1], p[2], t[1].et0, t[1].et1, 
GetNmlVec[t[1].et0, p[1]], GetNmlVec[t[1].et1, p[2], TRUE], 0.5, tol];
[v2, t20, t21, flat2] ← CurveDivideTan[
context, p[2], p[0], t[2].et0, t[2].et1, 
GetNmlVec[t[2].et0, p[2]], GetNmlVec[t[2].et1, p[0], TRUE], 0.5, tol];
IF flat0 
AND flat1 
AND flat2 
AND stopIfStraight     
-- all straight? then done
THEN TnsrQuadDisplay[context, p, recurseLimit, tol];     -- display as polygon
 
Get inner edges from midpoint to opposite vertex curves
tm0.et0 ← GetSlopeVec[ [v0.shade.exn, v0.shade.eyn, v0.shade.ezn], Add[t10.et0, t21.et1] ];
tm0.et0 ← ScaleTangent[ tm0.et0, DiffPosnsCtlPt[p[2].coord, v0.coord, $Eye] ];
tm0.et1 ← GetSlopeVec[ [p[2].shade.exn, p[2].shade.eyn, p[2].shade.ezn], Add[t20.et0, t11.et1]];
tm0.et1 ← ScaleTangent[ tm0.et1, DiffPosnsCtlPt[v0.coord, p[2].coord, $Eye] ];
tm1.et0 ← GetSlopeVec[ [v1.shade.exn, v1.shade.eyn, v1.shade.ezn], Add[t20.et0, t01.et1]];
tm1.et0 ← ScaleTangent[ tm1.et0, DiffPosnsCtlPt[p[0].coord, v1.coord, $Eye] ];
tm1.et1 ← GetSlopeVec[ [p[0].shade.exn, p[0].shade.eyn, p[0].shade.ezn], Add[t00.et0, t21.et1]];
tm1.et1 ← ScaleTangent[ tm1.et1, DiffPosnsCtlPt[v1.coord, p[0].coord, $Eye] ];
tm2.et0 ← GetSlopeVec[ [v2.shade.exn, v2.shade.eyn, v2.shade.ezn], Add[t00.et0, t11.et1]];
tm2.et0 ← ScaleTangent[ tm2.et0, DiffPosnsCtlPt[p[1].coord, v2.coord, $Eye] ];
tm2.et1 ← GetSlopeVec[ [p[1].shade.exn, p[1].shade.eyn, p[1].shade.ezn], Add[t10.et0, t01.et1]];
tm2.et1 ← ScaleTangent[ tm2.et1, DiffPosnsCtlPt[v2.coord, p[1].coord, $Eye] ];
Split inner edges at 1/3 point and average for ctr. point
[vCtr1, tm0, , ] ← CurveDivideTan[ 
context, v0, p[2], tm0.et0, tm0.et1, 
GetNmlVec[tm0.et0, v0], GetNmlVec[tm0.et1, p[2], TRUE], 1.0/3.0, tol ];
[vCtr2, tm1, , ] ← CurveDivideTan[ 
context, v1, p[0], tm1.et0, tm1.et1, 
GetNmlVec[tm1.et0, v1], GetNmlVec[tm1.et1, p[0], TRUE], 1.0/3.0, tol ];
[vCtr3, tm2, , ] ← CurveDivideTan[ 
context, v2, p[1], tm2.et0, tm2.et1, 
GetNmlVec[tm2.et0, v2], GetNmlVec[tm2.et1, p[1], TRUE], 1.0/3.0, tol ];
[[vCtr.coord.ex, vCtr.coord.ey, vCtr.coord.ez]] ←  Div[     
-- average positions
Add[
[vCtr1.coord.ex, vCtr1.coord.ey, vCtr1.coord.ez], 
Add[
[vCtr2.coord.ex, vCtr2.coord.ey, vCtr2.coord.ez],
[vCtr3.coord.ex, vCtr3.coord.ey, vCtr3.coord.ez]
]
], 
3.0
];
[[vCtr.shade.exn, vCtr.shade.eyn, vCtr.shade.ezn]] ← Div[    
-- average normals
Add[
[vCtr1.shade.exn, vCtr1.shade.eyn, vCtr1.shade.ezn], 
Add[
[vCtr2.shade.exn, vCtr2.shade.eyn, vCtr2.shade.ezn],
[vCtr3.shade.exn, vCtr3.shade.eyn, vCtr3.shade.ezn]
]
], 
3.0
];
FOR i: 
NAT 
IN [0..3) 
DO
outPatch[i] ← GetPatch[4];     -- allocate 4 point patch
outPatch[i].type ← p.type;
outPatch[i].oneSided ← p.oneSided;
outPatch[i].nVtces ← 4;
outPatch[i].clipState ← p.clipState;
outPatch[i].dir ← p.dir; 
outPatch[i].renderData ← p.renderData;
outPatch[i].props ← p.props;
ENDLOOP;
 
{ 
OPEN v0.coord;    clip ← G3dClipXfmShade.GetClipCodeForPt[context, [ ex, ey, ez] ];
IF clip = NoneOut 
THEN [ [sx, sy, sz] ] ← G3dClipXfmShade.XfmPtToDisplay[ context, [ex, ey, ez], shape ];  };
 
{ 
OPEN v1.coord;    clip ← G3dClipXfmShade.GetClipCodeForPt[context, [ ex, ey, ez] ];
IF clip = NoneOut 
THEN [ [sx, sy, sz] ] ← G3dClipXfmShade.XfmPtToDisplay[ context, [ex, ey, ez], shape ];  };
 
{ 
OPEN v2.coord;    clip ← G3dClipXfmShade.GetClipCodeForPt[context, [ ex, ey, ez] ];
IF clip = NoneOut 
THEN [ [sx, sy, sz] ] ← G3dClipXfmShade.XfmPtToDisplay[ context, [ex, ey, ez], shape ];  };
 
{ 
OPEN vCtr.coord;    clip ← G3dClipXfmShade.GetClipCodeForPt[context, [ ex, ey, ez] ];
IF clip = NoneOut 
THEN [ [sx, sy, sz] ] ← G3dClipXfmShade.XfmPtToDisplay[ context, [ex, ey, ez], shape ];  };
 
outPatch[0][0] ← p[0];   outPatch[0][1] ← v0;   outPatch[0][2] ← vCtr;   outPatch[0][3] ← v2;
outPatch[1][0] ← p[1];   outPatch[1][1] ← v1;   outPatch[1][2] ← vCtr;   outPatch[1][3] ← v0;
outPatch[2][0] ← p[2];   outPatch[2][1] ← v2;   outPatch[2][2] ← vCtr;   outPatch[2][3] ← v1;
outPatch[0].props ← PutPropSafely[ outPatch[0].props, $Tangents, 
NEW[TangentQuad ←
[t00, tm0, [tm2.t1, tm2.et1, tm2.t0, tm2.et0], t21] ] ];
outPatch[1].props ← PutPropSafely[ outPatch[1].props, $Tangents, 
NEW[TangentQuad ←
[t10, tm1, [tm0.t1, tm0.et1, tm0.t0, tm0.et0], t01] ] ];
outPatch[2].props ← PutPropSafely[ outPatch[2].props, $Tangents, 
NEW[TangentQuad ←
[t20, tm2, [tm1.t1, tm1.et1, tm1.t0, tm1.et0], t11] ] ];
FOR i: NAT IN [0..3) DO  G3dClipXfmShade.GetPatchClipState[ outPatch[i] ];  ENDLOOP; --bad!!
outPatch.length ← 3;
FOR i: 
NAT 
IN [0..3) 
DO 
TnsrQuadDisplay[ context, outPatch[i], 0, tol ];  ReleasePatch[outPatch[i]];
ENDLOOP;
 
};
  
 
SubdivideTnsrQuad: 
PROC[context: Context, p: 
REF Patch, level: 
NAT, tol: 
REAL]        
RETURNS[PatchSequence] ~ {
Divide quadrangular patch into four subquadrangles
shape: Shape ← NARROW[ GetProp[p.props, $Shape] ];
v0, v1, v2, v3, vCtr, vCtr2: CtlPtInfo;  flat0, flat1, flat2, flat3: BOOLEAN;
t: REF TangentQuad ← NARROW[GetProp[p.props, $Tangents] ];
t00, t01, t10, t11, t20, t21, t30, t31, tm0, tm1, tm2, tm3: TangentSet;
outPatch: PatchSequence ← NEW[PatchSequenceRep[4]];
Find midpoints and midslopes for each side
[v0, t00, t01, flat0] ← CurveDivideTan[ 
context, p[0], p[1], t[0].et0, t[0].et1, 
GetNmlVec[t[0].et0, p[0]], GetNmlVec[t[0].et1, p[1], TRUE], 0.5, tol ];
[v1, t10, t11, flat1] ← CurveDivideTan[
context, p[1], p[2], t[1].et0, t[1].et1, 
GetNmlVec[t[1].et0, p[1]], GetNmlVec[t[1].et1, p[2], TRUE], 0.5, tol];
[v2, t20, t21, flat2] ← CurveDivideTan[
context, p[2], p[3], t[2].et0, t[2].et1, 
GetNmlVec[t[2].et0, p[2]], GetNmlVec[t[2].et1, p[3], TRUE], 0.5, tol];
[v3, t30, t31, flat3] ← CurveDivideTan[
context, p[3], p[0], t[3].et0, t[3].et1, 
GetNmlVec[t[3].et0, p[3]], GetNmlVec[t[3].et1, p[0], TRUE], 0.5, tol];
IF flat0 
AND flat1 
AND flat2 
AND flat3 
AND stopIfStraight  
-- all straight? then done
THEN RETURN[NIL];
 
Get inner edge endpoint tangents from opposite midpoints
- first project direction given by endpoint cross-tangents on plane given by normal
- Then scale direction by distance to opposite midpoint
 
tm0.et0 ← GetSlopeVec[ [v0.shade.exn, v0.shade.eyn, v0.shade.ezn], Add[t10.et0, t31.et1] ];
tm0.et0 ← ScaleTangent[ tm0.et0, DiffPosnsCtlPt[v2.coord, v0.coord, $Eye] ];
tm0.et1 ← GetSlopeVec[ [v2.shade.exn, v2.shade.eyn, v2.shade.ezn], Add[t11.et1, t30.et0] ];
tm0.et1 ← ScaleTangent[ tm0.et1, DiffPosnsCtlPt[v0.coord, v2.coord, $Eye] ];
tm1.et0 ← GetSlopeVec[ [v1.shade.exn, v1.shade.eyn, v1.shade.ezn], Add[t20.et0, t01.et1] ];
tm1.et0 ← ScaleTangent[ tm1.et0, DiffPosnsCtlPt[v3.coord, v1.coord, $Eye] ];
tm1.et1 ← GetSlopeVec[ [v3.shade.exn, v3.shade.eyn, v3.shade.ezn], Add[t21.et1, t00.et0] ];
tm1.et1 ← ScaleTangent[ tm1.et1, DiffPosnsCtlPt[v1.coord, v3.coord, $Eye] ];
tm0.et0 ← GetSlopeVec[ [v0.shade.exn, v0.shade.eyn, v0.shade.ezn],
        DiffPosnsCtlPt[v2.coord, v0.coord, $Eye] ];
tm0.et1 ← GetSlopeVec[ [v2.shade.exn, v2.shade.eyn, v2.shade.ezn], 
        DiffPosnsCtlPt[v0.coord, v2.coord, $Eye] ];
tm1.et0 ← GetSlopeVec[ [v1.shade.exn, v1.shade.eyn, v1.shade.ezn],
        DiffPosnsCtlPt[v3.coord, v1.coord, $Eye] ];
tm1.et1 ← GetSlopeVec[ [v3.shade.exn, v3.shade.eyn, v3.shade.ezn], 
        DiffPosnsCtlPt[v1.coord, v3.coord, $Eye] ];
Get center point, normal and cross tangents
[vCtr, tm0, tm2, ] ← CurveDivideTan[ 
context, v0, v2, tm0.et0, tm0.et1, 
GetNmlVec[tm0.et0, v0], GetNmlVec[tm0.et1, v2, TRUE], 0.5, tol ];
[vCtr2, tm1, tm3, ] ← CurveDivideTan[ 
context, v1, v3, tm1.et0, tm1.et1, 
GetNmlVec[tm1.et0, v1], GetNmlVec[tm1.et1, v3, TRUE], 0.5, tol ];
[[vCtr.coord.ex, vCtr.coord.ey, vCtr.coord.ez]] ←  Div[       
-- average
Add[
[vCtr.coord.ex, vCtr.coord.ey, vCtr.coord.ez], 
[vCtr2.coord.ex, vCtr2.coord.ey, vCtr2.coord.ez]
], 
2
];
[[vCtr.shade.exn, vCtr.shade.eyn, vCtr.shade.ezn]] ← Nmlize[ Cross[ tm2.et0 , tm3.et0 ] ];
FOR i: 
NAT 
IN [0..4) 
DO
outPatch[i] ← GetPatch[4]; -- 4 point patch, released by display action
outPatch[i].type ← p.type;
outPatch[i].oneSided ← p.oneSided;
outPatch[i].nVtces ← 4;
outPatch[i].clipState ← p.clipState;
outPatch[i].dir ← p.dir; 
outPatch[i].renderData ← p.renderData;
outPatch[i].props ← p.props;
ENDLOOP;
 
{ 
OPEN v0.coord;    clip ← G3dClipXfmShade.GetClipCodeForPt[context, [ ex, ey, ez] ];
IF clip = NoneOut 
THEN [ [sx, sy, sz] ] ← G3dClipXfmShade.XfmPtToDisplay[ context, [ex, ey, ez], shape ];  };
 
{ 
OPEN v1.coord;    clip ← G3dClipXfmShade.GetClipCodeForPt[context, [ ex, ey, ez] ];
IF clip = NoneOut 
THEN [ [sx, sy, sz] ] ← G3dClipXfmShade.XfmPtToDisplay[ context, [ex, ey, ez], shape ];  };
 
{ 
OPEN v2.coord;    clip ← G3dClipXfmShade.GetClipCodeForPt[context, [ ex, ey, ez] ];
IF clip = NoneOut 
THEN [ [sx, sy, sz] ] ← G3dClipXfmShade.XfmPtToDisplay[ context, [ex, ey, ez], shape ];  };
 
{ 
OPEN v3.coord;    clip ← G3dClipXfmShade.GetClipCodeForPt[context, [ ex, ey, ez] ];
IF clip = NoneOut 
THEN [ [sx, sy, sz] ] ← G3dClipXfmShade.XfmPtToDisplay[ context, [ex, ey, ez], shape ];  };
 
{ 
OPEN vCtr.coord;    clip ← G3dClipXfmShade.GetClipCodeForPt[context, [ ex, ey, ez] ];
IF clip = NoneOut 
THEN [ [sx, sy, sz] ] ← G3dClipXfmShade.XfmPtToDisplay[ context, [ex, ey, ez], shape ];  };
 
outPatch[0][0] ← p[0];   outPatch[0][1] ← v0;   outPatch[0][2] ← vCtr;   outPatch[0][3] ← v3;
outPatch[1][0] ← p[1];   outPatch[1][1] ← v1;   outPatch[1][2] ← vCtr;   outPatch[1][3] ← v0;
outPatch[2][0] ← p[2];   outPatch[2][1] ← v2;   outPatch[2][2] ← vCtr;   outPatch[2][3] ← v1;
outPatch[3][0] ← p[3];   outPatch[3][1] ← v3;   outPatch[3][2] ← vCtr;   outPatch[3][3] ← v2;
IF t # 
NIL 
THEN {
outPatch[0].props ← PutPropSafely[ outPatch[0].props, $Tangents, 
NEW[TangentQuad ←
[t00, tm0, tm3, t31] ] ];
outPatch[1].props ← PutPropSafely[ outPatch[1].props, $Tangents, 
NEW[TangentQuad ←
[t10, tm1, [tm0.t1, tm0.et1, tm0.t0, tm0.et0], t01] ] ];
outPatch[2].props ← PutPropSafely[ outPatch[2].props, $Tangents, 
NEW[TangentQuad ←
[t20, [tm2.t1, tm2.et1, tm2.t0, tm2.et0], [tm1.t1, tm1.et1, tm1.t0, tm1.et0], t11] ] ];
outPatch[3].props ← PutPropSafely[ outPatch[3].props, $Tangents, 
NEW[TangentQuad ←
[t30, [tm3.t1, tm3.et1, tm3.t0, tm3.et0], tm2, t21] ] ];
};
 
FOR i: NAT IN [0..4) DO  G3dClipXfmShade.GetPatchClipState[ outPatch[i] ];  ENDLOOP; --bad!!
outPatch.length ← 4;
RETURN[ outPatch ]; -- return four sub-patches
};