This commit was generated by cvs2svn to compensate for changes in r2,
[btb/d2x.git] / 3d / clipper.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13 #include <conf.h>
14 #include "fix.h"
15 #include "vecmat.h"
16 #include "gr.h"
17 #include "3d.h"
18 #include "globvars.h"
19 #include "clipper.h"
20 #include "error.h"
21
22 int free_point_num=0;
23
24 g3s_point temp_points[MAX_POINTS_IN_POLY];
25 g3s_point *free_points[MAX_POINTS_IN_POLY];
26
27 void init_free_points(void)
28 {
29         int i;
30
31         for (i=0;i<MAX_POINTS_IN_POLY;i++)
32                 free_points[i] = &temp_points[i];
33 }
34
35
36 g3s_point *get_temp_point()
37 {
38         g3s_point *p;
39
40         Assert (free_point_num < MAX_POINTS_IN_POLY );
41         p = free_points[free_point_num++];
42
43         p->p3_flags = PF_TEMP_POINT;
44
45         return p;
46 }
47
48 void free_temp_point(g3s_point *p)
49 {
50         Assert(p->p3_flags & PF_TEMP_POINT);
51
52         free_points[--free_point_num] = p;
53
54         p->p3_flags &= ~PF_TEMP_POINT;
55 }
56
57 //clips an edge against one plane. 
58 g3s_point *clip_edge(int plane_flag,g3s_point *on_pnt,g3s_point *off_pnt)
59 {
60         fix psx_ratio;
61         fix a,b,kn,kd;
62         g3s_point *tmp;
63
64         //compute clipping value k = (xs-zs) / (xs-xe-zs+ze)
65         //use x or y as appropriate, and negate x/y value as appropriate
66
67         if (plane_flag & (CC_OFF_RIGHT | CC_OFF_LEFT)) {
68                 a = on_pnt->p3_x;
69                 b = off_pnt->p3_x;
70         }
71         else {
72                 a = on_pnt->p3_y;
73                 b = off_pnt->p3_y;
74         }
75
76         if (plane_flag & (CC_OFF_LEFT | CC_OFF_BOT)) {
77                 a = -a;
78                 b = -b;
79         }
80
81         kn = a - on_pnt->p3_z;                                          //xs-zs
82         kd = kn - b + off_pnt->p3_z;                            //xs-zs-xe+ze
83
84         tmp = get_temp_point();
85
86         psx_ratio = fixdiv( kn, kd );
87
88         
89 // PSX_HACK!!!!
90 //      tmp->p3_x = on_pnt->p3_x + fixmuldiv(off_pnt->p3_x-on_pnt->p3_x,kn,kd);
91 //      tmp->p3_y = on_pnt->p3_y + fixmuldiv(off_pnt->p3_y-on_pnt->p3_y,kn,kd);
92
93         tmp->p3_x = on_pnt->p3_x + fixmul( (off_pnt->p3_x-on_pnt->p3_x), psx_ratio);
94         tmp->p3_y = on_pnt->p3_y + fixmul( (off_pnt->p3_y-on_pnt->p3_y), psx_ratio);
95
96         if (plane_flag & (CC_OFF_TOP|CC_OFF_BOT))
97                 tmp->p3_z = tmp->p3_y;
98         else
99                 tmp->p3_z = tmp->p3_x;
100
101         if (plane_flag & (CC_OFF_LEFT|CC_OFF_BOT))
102                 tmp->p3_z = -tmp->p3_z;
103
104         if (on_pnt->p3_flags & PF_UVS) {
105 // PSX_HACK!!!!
106 //              tmp->p3_u = on_pnt->p3_u + fixmuldiv(off_pnt->p3_u-on_pnt->p3_u,kn,kd);
107 //              tmp->p3_v = on_pnt->p3_v + fixmuldiv(off_pnt->p3_v-on_pnt->p3_v,kn,kd);
108                 tmp->p3_u = on_pnt->p3_u + fixmul((off_pnt->p3_u-on_pnt->p3_u), psx_ratio);
109                 tmp->p3_v = on_pnt->p3_v + fixmul((off_pnt->p3_v-on_pnt->p3_v), psx_ratio);
110
111                 tmp->p3_flags |= PF_UVS;
112         }
113
114         if (on_pnt->p3_flags & PF_LS) {
115 // PSX_HACK
116 //              tmp->p3_r = on_pnt->p3_r + fixmuldiv(off_pnt->p3_r-on_pnt->p3_r,kn,kd);
117 //              tmp->p3_g = on_pnt->p3_g + fixmuldiv(off_pnt->p3_g-on_pnt->p3_g,kn,kd);
118 //              tmp->p3_b = on_pnt->p3_b + fixmuldiv(off_pnt->p3_b-on_pnt->p3_b,kn,kd);
119
120                 tmp->p3_l = on_pnt->p3_l + fixmul((off_pnt->p3_l-on_pnt->p3_l), psx_ratio);
121
122                 tmp->p3_flags |= PF_LS;
123         }
124
125         g3_code_point(tmp);
126
127         return tmp;     
128 }
129
130 //clips a line to the viewing pyramid.
131 void clip_line(g3s_point **p0,g3s_point **p1,ubyte codes_or)
132 {
133         int plane_flag;
134         g3s_point *old_p1;
135
136         //might have these left over
137         (*p0)->p3_flags &= ~(PF_UVS|PF_LS);
138         (*p1)->p3_flags &= ~(PF_UVS|PF_LS);
139
140         for (plane_flag=1;plane_flag<16;plane_flag<<=1)
141                 if (codes_or & plane_flag) {
142
143                         if ((*p0)->p3_codes & plane_flag)
144                                 {g3s_point *t=*p0; *p0=*p1; *p1=t;}     //swap!
145
146                         old_p1 = *p1;
147
148                         *p1 = clip_edge(plane_flag,*p0,*p1);
149
150                         if (old_p1->p3_flags & PF_TEMP_POINT)
151                                 free_temp_point(old_p1);
152                 }
153
154 }
155
156
157 int clip_plane(int plane_flag,g3s_point **src,g3s_point **dest,int *nv,g3s_codes *cc)
158 {
159         int i;
160         g3s_point **save_dest=dest;
161
162         //copy first two verts to end
163         src[*nv] = src[0];
164         src[*nv+1] = src[1];
165
166         cc->and = 0xff; cc->or = 0;
167
168         for (i=1;i<=*nv;i++) {
169
170                 if (src[i]->p3_codes & plane_flag) {                            //cur point off?
171
172                         if (! (src[i-1]->p3_codes & plane_flag)) {      //prev not off?
173
174                                 *dest = clip_edge(plane_flag,src[i-1],src[i]);
175                                 cc->or  |= (*dest)->p3_codes;
176                                 cc->and &= (*dest)->p3_codes;
177                                 dest++;
178                         }
179
180                         if (! (src[i+1]->p3_codes & plane_flag)) {
181
182                                 *dest = clip_edge(plane_flag,src[i+1],src[i]);
183                                 cc->or  |= (*dest)->p3_codes;
184                                 cc->and &= (*dest)->p3_codes;
185                                 dest++;
186                         }
187
188                         //see if must free discarded point
189
190                         if (src[i]->p3_flags & PF_TEMP_POINT)
191                                 free_temp_point(src[i]);
192                 }
193                 else {                  //cur not off, copy to dest buffer
194
195                         *dest++ = src[i];
196
197                         cc->or  |= src[i]->p3_codes;
198                         cc->and &= src[i]->p3_codes;
199                 }
200         }
201
202         return (dest-save_dest);
203 }
204
205
206 g3s_point **clip_polygon(g3s_point **src,g3s_point **dest,int *nv,g3s_codes *cc)
207 {
208         int plane_flag;
209         g3s_point **t;
210
211         for (plane_flag=1;plane_flag<16;plane_flag<<=1)
212
213                 if (cc->or & plane_flag) {
214
215                         *nv = clip_plane(plane_flag,src,dest,nv,cc);
216
217                         if (cc->and)            //clipped away
218                                 return dest;
219
220                         t = src; src = dest; dest = t;
221
222                 }
223
224         return src;             //we swapped after we copied
225 }
226