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