]> icculus.org git repositories - taylor/freespace2.git/blob - src/render/3dclipper.cpp
Initial revision
[taylor/freespace2.git] / src / render / 3dclipper.cpp
1 /*
2  * $Logfile: /Freespace2/code/Render/3dClipper.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Polygon clipping functions
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:10  root
11  * Initial revision
12  *
13  * 
14  * 2     10/07/98 10:53a Dave
15  * Initial checkin.
16  * 
17  * 1     10/07/98 10:51a Dave
18  * 
19  * 13    4/10/98 5:20p John
20  * Changed RGB in lighting structure to be ubytes.  Removed old
21  * not-necessary 24 bpp software stuff.
22  * 
23  * 12    3/23/98 5:00p John
24  * Improved missile trails.  Made smooth alpha under hardware.  Made end
25  * taper.  Made trail touch weapon.
26  * 
27  * 11    3/16/98 4:51p John
28  * Added low-level code to clip all polygons against an arbritary plane.
29  * Took out all old model_interp_zclip and used this new method instead.  
30  * 
31  * 10    1/23/98 5:08p John
32  * Took L out of vertex structure used B (blue) instead.   Took all small
33  * fireballs out of fireball types and used particles instead.  Fixed some
34  * debris explosion things.  Restructured fireball code.   Restructured
35  * some lighting code.   Made dynamic lighting on by default. Made groups
36  * of lasers only cast one light.  Made fireballs not cast light.
37  * 
38  * 9     9/09/97 3:39p Sandeep
39  * warning level 4 bugs
40  * 
41  * 8     3/10/97 5:20p John
42  * Differentiated between Gouraud and Flat shading.  Since we only do flat
43  * shading as of now, we don't need to interpolate L in the outer loop.
44  * This should save a few percent.
45  * 
46  * 7     3/10/97 2:25p John
47  * Made pofview zbuffer.   Made textest work with new model code.  Took
48  * out some unnecessary Asserts in the 3d clipper.
49  * 
50  * 
51  * 6     12/23/96 11:00a John
52  * Restructured POF stuff to support LOD in one pof.
53  * 
54  * 5     11/06/96 2:33p John
55  * Added more asserts for checking that non-tiled UV's are between 0 and
56  * 1.0.    Put code in the model_init code that checks for polys that have
57  * a vertex duplicated and throws them out.
58  *
59  * $NoKeywords: $
60  */
61
62 #include "3dinternal.h"
63 #include "tmapper.h"
64
65 int free_point_num=0;
66
67 vertex temp_points[TMAP_MAX_VERTS];
68 vertex *free_points[TMAP_MAX_VERTS];
69
70 void init_free_points(void)
71 {
72         int i;
73
74         for (i=0;i<TMAP_MAX_VERTS;i++)
75                 free_points[i] = &temp_points[i];
76 }
77
78
79 vertex *get_temp_point()
80 {
81         vertex *p;
82
83         p = free_points[free_point_num++];
84
85         p->flags = PF_TEMP_POINT;
86
87         return p;
88 }
89
90 void free_temp_point(vertex *p)
91 {
92         Assert(p->flags & PF_TEMP_POINT);
93
94         free_points[--free_point_num] = p;
95
96         p->flags &= ~PF_TEMP_POINT;
97 }
98
99 //clips an edge against one plane.
100 vertex *clip_edge(int plane_flag,vertex *on_pnt,vertex *off_pnt, uint flags)
101 {
102         float ratio;
103         vertex *tmp;
104
105         tmp = get_temp_point();
106
107         if ( plane_flag & CC_OFF_USER ) {
108
109                 // Clip with user-defined plane
110                 vector w, ray_direction;
111                 float num,den;
112
113                 vm_vec_sub(&ray_direction,(vector *)&off_pnt->x,(vector *)&on_pnt->x);
114                         
115                 vm_vec_sub(&w,(vector *)&on_pnt->x,&G3_user_clip_point);
116         
117                 den = -vm_vec_dot(&G3_user_clip_normal,&ray_direction);
118                 if ( den == 0.0f ) {    // Ray & plane are parallel, so there is no intersection
119                         Int3(); // Get John
120                         ratio = 1.0f;
121                 } else {
122                         num =  vm_vec_dot(&G3_user_clip_normal,&w);
123         
124                         ratio = num / den;
125                 }
126
127                 tmp->x = on_pnt->x + (off_pnt->x-on_pnt->x) * ratio;
128                 tmp->y = on_pnt->y + (off_pnt->y-on_pnt->y) * ratio;
129                 tmp->z = on_pnt->z + (off_pnt->z-on_pnt->z) * ratio;
130
131         } else {
132                 float a,b,kn,kd;
133
134                 //compute clipping value k = (xs-zs) / (xs-xe-zs+ze)
135                 //use x or y as appropriate, and negate x/y value as appropriate
136
137                 if (plane_flag & (CC_OFF_RIGHT | CC_OFF_LEFT)) {
138                         a = on_pnt->x;
139                         b = off_pnt->x;
140                 }
141                 else {
142                         a = on_pnt->y;
143                         b = off_pnt->y;
144                 }
145
146                 if (plane_flag & (CC_OFF_LEFT | CC_OFF_BOT)) {
147                         a = -a;
148                         b = -b;
149                 }
150
151                 kn = a - on_pnt->z;                                             //xs-zs
152                 kd = kn - b + off_pnt->z;                               //xs-zs-xe+ze
153
154                 ratio = kn / kd;
155
156                 tmp->x = on_pnt->x + (off_pnt->x-on_pnt->x) * ratio;
157                 tmp->y = on_pnt->y + (off_pnt->y-on_pnt->y) * ratio;
158
159                 if (plane_flag & (CC_OFF_TOP|CC_OFF_BOT))       {
160                         tmp->z = tmp->y;
161                 } else {
162                         tmp->z = tmp->x;
163                 }
164
165                 if (plane_flag & (CC_OFF_LEFT|CC_OFF_BOT))
166                         tmp->z = -tmp->z;
167
168         }
169
170         if (flags & TMAP_FLAG_TEXTURED) {
171                 tmp->u = on_pnt->u + (off_pnt->u-on_pnt->u) * ratio;
172                 tmp->v = on_pnt->v + (off_pnt->v-on_pnt->v) * ratio;
173         }
174
175         if (flags & TMAP_FLAG_GOURAUD ) {
176                 if (flags & TMAP_FLAG_RAMP) {
177
178                         float on_b, off_b;
179
180                         on_b = i2fl(on_pnt->b);
181                         off_b = i2fl(off_pnt->b);
182
183                         tmp->b = ubyte(fl2i(on_b + (off_b-on_b) * ratio));
184                 }
185                 if (flags & TMAP_FLAG_RGB) {
186                         float on_r, on_b, on_g;
187                         float off_r, off_b, off_g;
188
189                         on_r = i2fl(on_pnt->r);
190                         off_r = i2fl(off_pnt->r);
191                         on_g = i2fl(on_pnt->g);
192                         off_g = i2fl(off_pnt->g);
193
194                         on_b = i2fl(on_pnt->b);
195                         off_b = i2fl(off_pnt->b);
196
197                         tmp->r = ubyte(fl2i(on_r + (off_r-on_r) * ratio));
198                         tmp->g = ubyte(fl2i(on_g + (off_g-on_g) * ratio));
199                         tmp->b = ubyte(fl2i(on_b + (off_b-on_b) * ratio));
200                 }
201         }
202
203         if (flags & TMAP_FLAG_ALPHA) {
204
205                 float on_a, off_a;
206
207                 on_a = i2fl(on_pnt->a);
208                 off_a = i2fl(off_pnt->a);
209
210                 tmp->a = ubyte(fl2i(on_a + (off_a-on_a) * ratio));
211         }
212
213         g3_code_vertex(tmp);
214
215         return tmp;     
216 }
217
218 //clips a line to the viewing pyramid.
219 void clip_line(vertex **p0,vertex **p1,ubyte codes_or, uint flags)
220 {
221         int plane_flag;
222         vertex *old_p1;
223
224         for (plane_flag=1;plane_flag<=CC_OFF_USER;plane_flag<<=1)
225                 if (codes_or & plane_flag) {
226
227                         if ((*p0)->codes & plane_flag)
228                                 {vertex *t=*p0; *p0=*p1; *p1=t;}        //swap!
229
230                         old_p1 = *p1;
231
232                         *p1 = clip_edge(plane_flag,*p0,*p1,flags);
233                         codes_or = (unsigned char)((*p0)->codes | (*p1)->codes);        //get new codes
234
235                         if (old_p1->flags & PF_TEMP_POINT)
236                                 free_temp_point(old_p1);
237                 }
238
239 }
240
241 int clip_plane(int plane_flag,vertex **src,vertex **dest,int *nv,ccodes *cc,uint flags)
242 {
243         int i;
244         vertex **save_dest=dest;
245
246         //copy first two verts to end
247         src[*nv] = src[0];
248         src[*nv+1] = src[1];
249
250         cc->and = 0xff; cc->or = 0;
251
252         for (i=1;i<=*nv;i++) {
253
254                 if (src[i]->codes & plane_flag) {                               //cur point off?
255
256                         if (! (src[i-1]->codes & plane_flag)) { //prev not off?
257
258                                 *dest = clip_edge(plane_flag,src[i-1],src[i],flags);
259                                 cc->or  |= (*dest)->codes;
260                                 cc->and &= (*dest)->codes;
261                                 dest++;
262                         }
263
264                         if (! (src[i+1]->codes & plane_flag)) {
265
266                                 *dest = clip_edge(plane_flag,src[i+1],src[i],flags);
267                                 cc->or  |= (*dest)->codes;
268                                 cc->and &= (*dest)->codes;
269                                 dest++;
270                         }
271
272                         //see if must free discarded point
273
274                         if (src[i]->flags & PF_TEMP_POINT)
275                                 free_temp_point(src[i]);
276                 }
277                 else {                  //cur not off, copy to dest buffer
278
279                         *dest++ = src[i];
280
281                         cc->or  |= src[i]->codes;
282                         cc->and &= src[i]->codes;
283                 }
284         }
285
286         return (dest-save_dest);
287 }
288
289
290 vertex **clip_polygon(vertex **src,vertex **dest,int *nv,ccodes *cc,uint flags)
291 {
292         int plane_flag;
293         vertex **t;
294
295         for (plane_flag=1;plane_flag<=CC_OFF_USER;plane_flag<<=1)
296
297                 if (cc->or & plane_flag) {
298
299                         *nv = clip_plane(plane_flag,src,dest,nv,cc,flags);
300
301                         if (cc->and)            //clipped away
302                                 return dest;
303
304                         t = src; src = dest; dest = t;
305
306                 }
307
308         return src;             //we swapped after we copied
309 }
310
311
312
313
314
315
316
317