clip.c
4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include "graphic.h"
/*--------------------------------------------------*/
do_bf_cull( va, vb, vc)
/* return true if backface */
struct Vertex *va, *vb, *vc;
/* XXXX makes sense to integrate this with setup to reuse pleq terms */
{
int xa, ya, xb, yb;
int sign;
xa = va->x;
ya = va->y;
xb = vb->x - xa;
yb = vb->y - ya;
xa = vc->x - xa;
ya = vc->y - ya;
sign = (int)((float)xa*(float)yb-(float)xb*(float)ya);
if (sign == 0) return( en_bf_cull); /* no area */
/* shift so all sign bits */
return( ((sign >> 31) ^ bf_cull_sign) & en_bf_cull);
}
/*--------------------------------------------------*/
do_clip( cc_clip, va, vb, vtx, vcount)
int cc_clip; /* OR of clip codes of input vertices */
struct Vertex **va, **vb; /* vertex list and working list */
struct Vertex *vtx; /* intput vertices, new added after vcount */
int *vcount; /* number of vertices */
{
struct Vertex **vpi, **vpo, **vpt; /* list swap pointers */
struct Vertex *vp, *vn; /* previous and next vertex */
struct Vertex *vins, *vout; /* inside and outside vertex */
int vci, vco, vc; /* input, output, local vertex count */
int vcn; /* new vertex index */
int plane, count, flag, index; /* clip plane references */
int inside, last_in; /* vertex status */
int xi, xo, wi, wo; /* coordinates */
int wone; /* offset to clip < w */
int num, den; /* clip distance num/den */
vpi = va;
vpo = vb;
vci = *vcount;
vcn = vci; /* put new vertices after the input ones */
count = 0; /* number of planes clipped */
for (plane=0; plane<CLIP_PLANE; plane++) {
flag = 1 << plane; /* clip plane to test */
if (!(cc_clip & flag)) continue; /* nothing out this plane */
cc_clip = 0; /* reset for new vertices */
count++; /* number of planes clipped */
index = plane >> 1; /* coord being clipped */
vco = 0; /* no ouput vertices */
vn = vpi[vci-1]; /* pointer to last vertex */
inside = !(vn->cc & flag); /* true if clip bit zero */
for(vc=0; vc<vci; vc++) {
last_in = inside; /* save previous vertex status */
vp = vn;
vn = vpi[vc]; /* next vertex status */
inside = !(vn->cc & flag);
/* detect crossing */
if (inside ^ last_in) { /* true if only one is zero */
/* clip always in-to-out so shared edges have exact same vertex */
vout = vn; vins = vp;
if (inside) { vins = vn; vout = vp; }
wo = vout->cw;
xo = get_xyz( vout, index);
wi = vins->cw;
xi = get_xyz( vins, index);
wone = 1;
if (!(plane & 1)) { /* negative w plane */
wi = -wi; wo = -wo; wone = -1; }
/* for clipped coord equal to one less than w:
wi + (wo - wi) * d - 1 = xi + (xo - xi) * d;
or, d = (wi - xi - 1) / (xo - xi - wo + wi); */
num = wi - xi - wone;
den = xo - xi - wo + wi;
clip_vertex( num, den, vins, vout, &vtx[vcn]);
vpo[vco] = &vtx[vcn]; /* copy pointer */
cc_clip |= vpo[vco]->cc; /* update clip code */
vco++; /* inc output count */
vcn++; /* inc vertex count */
}
if (inside) { /* copy inside vertex */
vpo[vco] = vpi[vc]; /* copy pointer */
cc_clip |= vpo[vco]->cc; /* update clip code */
vco++; /* inc output count */
}
}
vpt = vpi; vpi = vpo; vpo = vpt; /* flip input and output lists */
vci = vco; /* input count is previous output count */
}
/* project the newly generated vertices (together here to possibly
pipeline the divides). XXXX better to do only the output ones. */
for (vc=*vcount; vc<vcn; vc++) do_project( &vtx[vc]);
*vcount = vci; /* update vertex count */
if (count & 1) /* odd number of planes, so copy output to input */
for (vc=0; vc<vco; vc++) va[vc] = vb[vc];
}
/*----------------------------*/
get_xyz( v, i)
/* XXXX vertex should be an array indexed by i instead of a structure */
struct Vertex *v;
int i;
{
if (i == 0) return( v->cx);
if (i == 1) return( v->cy);
return( v->cz);
}
/*----------------------------*/
clip_vertex( n, d, vi, vo, vn)
int n, d;
struct Vertex *vi, *vo, *vn;
{
/* XXXX should be vector ops */
int e, f, g;
divide_seed( d, &e);
divide_newt( d, e, &f);
g = (int)((float)n*f);
d = g;
/*
if (d != 0) d = (int)((float)DIV_RECP_FRAC*n/d);
*/
clip_attr( d, vi->r, vo->r, &vn->r);
clip_attr( d, vi->g, vo->g, &vn->g);
clip_attr( d, vi->b, vo->b, &vn->b);
clip_attr( d, vi->a, vo->a, &vn->a);
clip_attr( d, vi->s, vo->s, &vn->s);
clip_attr( d, vi->t, vo->t, &vn->t);
clip_attr( d, vi->cx, vo->cx, &vn->cx);
clip_attr( d, vi->cy, vo->cy, &vn->cy);
clip_attr( d, vi->cz, vo->cz, &vn->cz);
clip_attr( d, vi->cw, vo->cw, &vn->cw);
do_clip_test( vn); /* new flags for more plane tests */
/* project later after done clipping */
}
/*----------------------------*/
clip_attr( a, i, o, n)
int a, i, o, *n;
{
*n = i + (int)((float)(o-i)*a*(float)1.0/DIV_RECP_FRAC);
}
/*----------------------------*/