G3dClipImpl.mesa
Copyright Ó 1984, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, September 15, 1992 12:46 pm PDT
DIRECTORY G3dBasic, G3dClip, G3dMatrix;
G3dClipImpl: CEDAR PROGRAM
IMPORTS G3dMatrix
EXPORTS G3dClip
~ BEGIN
ClippedPair:  TYPE ~ G3dClip.ClippedPair;
ClippedTriple: TYPE ~ G3dClip.ClippedTriple;
Matrix:   TYPE ~ G3dClip.Matrix;
Quad:    TYPE ~ G3dClip.Quad;
Triple:   TYPE ~ G3dClip.Triple;
Wec:    TYPE ~ ARRAY[0..6) OF REAL;
Clipping operations on projected 3d points
AWec: PROC [xp: Quad] RETURNS [Wec] ~ {
Divide xp.x by aspect ratio if non-unity.
To clip to [0..1] cube:
RETURN[[xp.x, xp.w-xp.x, xp.y, xp.w-xp.y, xp.z, xp.w-xp.z]];
To clip to [-1..1] cube:
RETURN[[xp.w+xp.x, xp.w-xp.x, xp.w+xp.y, xp.w-xp.y, xp.z, xp.w-xp.z]];
};
Alphas: PUBLIC PROC [xp0, xp1: Quad] RETURNS [a0, a1: REAL, off: BOOL] ~ {
wec0: Wec ¬ AWec[xp0];
wec1: Wec ¬ AWec[xp1];
a0 ¬ 0.0;
a1 ¬ 1.0;
FOR i: NAT IN[0..6) DO
IF wec0[i] < 0.0
THEN {
IF wec1[i] < 0.0 THEN RETURN[a0, a1, TRUE];
a0 ¬ MAX[a0, wec0[i]/(wec0[i]-wec1[i])];
}
ELSE IF wec1[i] < 0.0 THEN
a1 ¬ MIN[a1, wec0[i]/(wec0[i]-wec1[i])];
IF a0 > a1 THEN RETURN[a0, a1, TRUE];
ENDLOOP;
RETURN[a0, a1, FALSE];
};
Frustum: PUBLIC PROC [p0, p1: Triple, m: Matrix] RETURNS [ct: ClippedTriple] ~ {
dif: Quad;
a0, a1, w0, w1: REAL;
xp0: Quad ¬ G3dMatrix.TransformH[p0, m];
xp1: Quad ¬ G3dMatrix.TransformH[p1, m];
[a0, a1, ct.off] ¬ Alphas[xp0, xp1];
IF ct.off THEN RETURN;
dif ¬ [xp1.x-xp0.x, xp1.y-xp0.y, xp1.z-xp0.z, xp1.w-xp0.w];
w0 ¬ 1.0/(xp0.w+a0*dif.w);
w1 ¬ 1.0/(xp0.w+a1*dif.w);
ct.c0 ¬ [w0*(xp0.x+a0*dif.x), w0*(xp0.y+a0*dif.y), w0*(xp0.z+a0*dif.z)];
ct.c1 ¬ [w1*(xp0.x+a1*dif.x), w1*(xp0.y+a1*dif.y), w1*(xp0.z+a1*dif.z)];
};
FrustumH: PUBLIC PROC [xp0, xp1: Quad] RETURNS [ct: ClippedTriple] ~ {
dif: Quad;
a0, a1, w0, w1: REAL;
[a0, a1, ct.off] ¬ Alphas[xp0, xp1];
IF ct.off THEN RETURN;
dif ¬ [xp1.x-xp0.x, xp1.y-xp0.y, xp1.z-xp0.z, xp1.w-xp0.w];
w0 ¬ 1.0/(xp0.w+a0*dif.w);
w1 ¬ 1.0/(xp0.w+a1*dif.w);
ct.c0 ¬ [w0*(xp0.x+a0*dif.x), w0*(xp0.y+a0*dif.y), w0*(xp0.z+a0*dif.z)];
ct.c1 ¬ [w1*(xp0.x+a1*dif.x), w1*(xp0.y+a1*dif.y), w1*(xp0.z+a1*dif.z)];
};
FrustumD: PUBLIC PROC [xp0, xp1: Quad] RETURNS [cp: ClippedPair] ~ {
dif: Quad;
a0, a1, w0, w1: REAL;
[a0, a1, cp.off] ¬ Alphas[xp0, xp1];
IF cp.off THEN RETURN;
dif ¬ [xp1.x-xp0.x, xp1.y-xp0.y, , xp1.w-xp0.w];
w0 ¬ 1.0/(xp0.w+a0*dif.w);
w1 ¬ 1.0/(xp0.w+a1*dif.w);
cp.c0 ¬ [w0*(xp0.x+a0*dif.x), w0*(xp0.y+a0*dif.y)];
cp.c1 ¬ [w1*(xp0.x+a1*dif.x), w1*(xp0.y+a1*dif.y)];
};
NearH: PUBLIC PROC [q0, q1: Quad] RETURNS [cp: ClippedPair] ~ {
w0, w1: REAL;
a0: REAL ¬ 0.0;
a1: REAL ¬ 1.0;
dx: REAL ¬ q1.x-q0.x;
dy: REAL ¬ q1.y-q0.y;
dw: REAL ¬ q1.w-q0.w;
sum0: REAL ¬ q0.w+q0.z;
sum1: REAL ¬ q1.w+q1.z;
IF sum0 < 0.0
THEN {
IF sum1 < 0.0 THEN RETURN[[[0, 0], [0, 0], TRUE]];
a0 ¬ sum0/(sum0-sum1);
}
ELSE IF sum1 < 0.0 THEN a1 ¬ sum0/(sum0-sum1);
IF a0 > a1 THEN RETURN[[[0, 0], [0, 0], TRUE]];
w0 ¬ IF a0 = 0.0 THEN q0.w ELSE q0.w+a0*dw;
w1 ¬ IF a1 = 1.0 THEN q1.w ELSE q0.w+a1*dw;
cp.c0 ¬ IF w0 = 0 THEN [q0.x+a0*dx, q0.y+a0*dy] ELSE [(q0.x+a0*dx)/w0, (q0.y+a0*dy)/w0];
cp.c1 ¬ IF w1 = 0 THEN [q0.x+a1*dx, q0.y+a1*dy] ELSE [(q0.x+a1*dx)/w1, (q0.y+a1*dy)/w1];
cp.off ¬ FALSE;
};
END.