1 /*
2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
3 *
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
6 * source.
7 *
8 */
9
10
11
12 #include "render/3dinternal.h"
13 #include "graphics/tmapper.h"
14
15
16 int free_point_num=0;
17
18 vertex temp_points[TMAP_MAX_VERTS];
19 vertex *free_points[TMAP_MAX_VERTS];
20
init_free_points(void)21 void init_free_points(void)
22 {
23 int i;
24
25 for (i=0;i<TMAP_MAX_VERTS;i++)
26 free_points[i] = &temp_points[i];
27 }
28
29
get_temp_point()30 vertex *get_temp_point()
31 {
32 vertex *p;
33
34 p = free_points[free_point_num++];
35
36 p->flags = PF_TEMP_POINT;
37
38 return p;
39 }
40
41
free_temp_point(vertex * p)42 void free_temp_point(vertex *p)
43 {
44 Assert(p->flags & PF_TEMP_POINT);
45
46 free_points[--free_point_num] = p;
47
48 p->flags &= ~PF_TEMP_POINT;
49 }
50
51
52 /**
53 * @brief Clips an edge against one plane.
54 */
clip_edge(int plane_flag,vertex * on_pnt,vertex * off_pnt,uint flags)55 vertex *clip_edge(int plane_flag,vertex *on_pnt,vertex *off_pnt, uint flags)
56 {
57 float ratio;
58 vertex *tmp;
59
60 tmp = get_temp_point();
61
62 if ( plane_flag & CC_OFF_USER ) {
63
64 // Clip with user-defined plane
65 vec3d w, ray_direction;
66 float num,den;
67
68 vm_vec_sub(&ray_direction,&off_pnt->world,&on_pnt->world);
69
70 vm_vec_sub(&w,&on_pnt->world,&G3_user_clip_point);
71
72 den = -vm_vec_dot(&G3_user_clip_normal,&ray_direction);
73 if ( den == 0.0f ) { // Ray & plane are parallel, so there is no intersection
74 Int3(); // Get John
75 ratio = 1.0f;
76 } else {
77 num = vm_vec_dot(&G3_user_clip_normal,&w);
78
79 ratio = num / den;
80 }
81
82 vm_vec_sub(&tmp->world, &off_pnt->world, &on_pnt->world);
83 vm_vec_scale(&tmp->world, ratio);
84 vm_vec_add2(&tmp->world, &on_pnt->world);
85
86 } else {
87 float a,b,kn,kd;
88
89 //compute clipping value k = (xs-zs) / (xs-xe-zs+ze)
90 //use x or y as appropriate, and negate x/y value as appropriate
91
92 if (plane_flag & (CC_OFF_RIGHT | CC_OFF_LEFT)) {
93 a = on_pnt->world.xyz.x;
94 b = off_pnt->world.xyz.x;
95 }
96 else {
97 a = on_pnt->world.xyz.y;
98 b = off_pnt->world.xyz.y;
99 }
100
101 if (plane_flag & (CC_OFF_LEFT | CC_OFF_BOT)) {
102 a = -a;
103 b = -b;
104 }
105
106 kn = a - on_pnt->world.xyz.z; //xs-zs
107 kd = kn - b + off_pnt->world.xyz.z; //xs-zs-xe+ze
108
109 ratio = kn / kd;
110
111 tmp->world.xyz.x = on_pnt->world.xyz.x + (off_pnt->world.xyz.x-on_pnt->world.xyz.x) * ratio;
112 tmp->world.xyz.y = on_pnt->world.xyz.y + (off_pnt->world.xyz.y-on_pnt->world.xyz.y) * ratio;
113
114 if (plane_flag & (CC_OFF_TOP|CC_OFF_BOT)) {
115 tmp->world.xyz.z = tmp->world.xyz.y;
116 } else {
117 tmp->world.xyz.z = tmp->world.xyz.x;
118 }
119
120 if (plane_flag & (CC_OFF_LEFT|CC_OFF_BOT))
121 tmp->world.xyz.z = -tmp->world.xyz.z;
122
123 }
124
125 if (flags & TMAP_FLAG_TEXTURED) {
126 tmp->texture_position.u = on_pnt->texture_position.u + (off_pnt->texture_position.u-on_pnt->texture_position.u) * ratio;
127 tmp->texture_position.v = on_pnt->texture_position.v + (off_pnt->texture_position.v-on_pnt->texture_position.v) * ratio;
128 }
129
130 if (flags & TMAP_FLAG_GOURAUD ) {
131 if (flags & TMAP_FLAG_RAMP) {
132
133 float on_b, off_b;
134
135 on_b = i2fl(on_pnt->b);
136 off_b = i2fl(off_pnt->b);
137
138 tmp->b = ubyte(fl2i(on_b + (off_b-on_b) * ratio));
139 }
140 if (flags & TMAP_FLAG_RGB) {
141 float on_r, on_b, on_g, onspec_r, onspec_g, onspec_b;
142 float off_r, off_b, off_g, offspec_r, offspec_g, offspec_b;
143
144 on_r = i2fl(on_pnt->r);
145 off_r = i2fl(off_pnt->r);
146
147 on_g = i2fl(on_pnt->g);
148 off_g = i2fl(off_pnt->g);
149
150 on_b = i2fl(on_pnt->b);
151 off_b = i2fl(off_pnt->b);
152
153
154 onspec_r = i2fl(on_pnt->spec_r);
155 offspec_r = i2fl(off_pnt->spec_r);
156
157 onspec_g = i2fl(on_pnt->spec_g);
158 offspec_g = i2fl(off_pnt->spec_g);
159
160 onspec_b = i2fl(on_pnt->spec_b);
161 offspec_b = i2fl(off_pnt->spec_b);
162
163
164 tmp->r = ubyte(fl2i(on_r + (off_r-on_r) * ratio));
165 tmp->g = ubyte(fl2i(on_g + (off_g-on_g) * ratio));
166 tmp->b = ubyte(fl2i(on_b + (off_b-on_b) * ratio));
167
168 tmp->spec_r = ubyte(fl2i(onspec_r + (offspec_r-onspec_r) * ratio));
169 tmp->spec_g = ubyte(fl2i(onspec_g + (offspec_g-onspec_g) * ratio));
170 tmp->spec_b = ubyte(fl2i(onspec_b + (offspec_b-onspec_b) * ratio));
171 }
172 }
173 else
174 {
175 tmp->spec_r=tmp->spec_g=tmp->spec_b=0;
176 }
177
178 if (flags & TMAP_FLAG_ALPHA) {
179
180 float on_a, off_a;
181
182 on_a = i2fl(on_pnt->a);
183 off_a = i2fl(off_pnt->a);
184
185 tmp->a = ubyte(fl2i(on_a + (off_a-on_a) * ratio));
186 }
187
188 g3_code_vertex(tmp);
189
190 return tmp;
191 }
192
193
194 /**
195 * @brief Clips a line to the viewing pyramid.
196 */
clip_line(vertex ** p0,vertex ** p1,ubyte codes_or,uint flags)197 void clip_line(vertex **p0,vertex **p1,ubyte codes_or, uint flags)
198 {
199 int plane_flag;
200 vertex *old_p1;
201
202 for (plane_flag=1;plane_flag<=CC_OFF_USER;plane_flag<<=1)
203 if (codes_or & plane_flag) {
204
205 if ((*p0)->codes & plane_flag)
206 {vertex *t=*p0; *p0=*p1; *p1=t;} //swap!
207
208 old_p1 = *p1;
209
210 *p1 = clip_edge(plane_flag,*p0,*p1,flags);
211 codes_or = (unsigned char)((*p0)->codes | (*p1)->codes); //get new codes
212
213 if (old_p1->flags & PF_TEMP_POINT)
214 free_temp_point(old_p1);
215 }
216
217 }
218
219 /**
220 * @brief Clips a plane to the viewing pyramid.
221 */
clip_plane(int plane_flag,vertex ** src,vertex ** dest,int * nv,ccodes * cc,uint flags)222 int clip_plane(int plane_flag,vertex **src,vertex **dest,int *nv,ccodes *cc,uint flags)
223 {
224 int i;
225 vertex **save_dest=dest;
226
227 //copy first two verts to end
228 src[*nv] = src[0];
229 src[*nv+1] = src[1];
230
231 cc->cc_and = 0xff;
232 cc->cc_or = 0;
233
234 for (i=1;i<=*nv;i++) {
235
236 if (src[i]->codes & plane_flag) { //cur point off?
237
238 if (! (src[i-1]->codes & plane_flag)) { //prev not off?
239
240 *dest = clip_edge(plane_flag,src[i-1],src[i],flags);
241 cc->cc_or |= (*dest)->codes;
242 cc->cc_and &= (*dest)->codes;
243 dest++;
244 }
245
246 if (! (src[i+1]->codes & plane_flag)) {
247
248 *dest = clip_edge(plane_flag,src[i+1],src[i],flags);
249 cc->cc_or |= (*dest)->codes;
250 cc->cc_and &= (*dest)->codes;
251 dest++;
252 }
253
254 //see if must free discarded point
255
256 if (src[i]->flags & PF_TEMP_POINT)
257 free_temp_point(src[i]);
258 }
259 else { //cur not off, copy to dest buffer
260
261 *dest++ = src[i];
262
263 cc->cc_or |= src[i]->codes;
264 cc->cc_and &= src[i]->codes;
265 }
266 }
267
268 return (dest-save_dest);
269 }
270
271 /**
272 * @brief Clips a polygon to the viewing pyramid.
273 */
clip_polygon(vertex ** src,vertex ** dest,int * nv,ccodes * cc,uint flags)274 vertex **clip_polygon(vertex **src,vertex **dest,int *nv,ccodes *cc,uint flags)
275 {
276 int plane_flag;
277 vertex **t;
278
279 for (plane_flag=1;plane_flag<=CC_OFF_USER;plane_flag<<=1)
280
281 if (cc->cc_or & plane_flag) {
282
283 *nv = clip_plane(plane_flag,src,dest,nv,cc,flags);
284
285 if (cc->cc_and) //clipped away
286 return dest;
287
288 t = src; src = dest; dest = t;
289
290 }
291
292 return src; //we swapped after we copied
293 }
294