1 /*
2 	r_aclip.c
3 
4 	clip routines for drawing Alias models directly to the screen
5 
6 	Copyright (C) 1996-1997  Id Software, Inc.
7 
8 	This program is free software; you can redistribute it and/or
9 	modify it under the terms of the GNU General Public License
10 	as published by the Free Software Foundation; either version 2
11 	of the License, or (at your option) any later version.
12 
13 	This program is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 	See the GNU General Public License for more details.
18 
19 	You should have received a copy of the GNU General Public License
20 	along with this program; if not, write to:
21 
22 		Free Software Foundation, Inc.
23 		59 Temple Place - Suite 330
24 		Boston, MA  02111-1307, USA
25 
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 
31 #include "QF/render.h"
32 
33 #include "d_local.h"
34 #include "r_internal.h"
35 
36 #ifdef PIC
37 # undef USE_INTEL_ASM //XXX asm pic hack
38 #endif
39 
40 static finalvert_t fv[2][8];
41 static auxvert_t av[8];
42 
43 /*
44 	R_Alias_clip_z
45 
46 	pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
47 */
48 static void
R_Alias_clip_z(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out)49 R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
50 {
51 	float       scale;
52 	auxvert_t  *pav0, *pav1, avout;
53 
54 	pav0 = &av[pfv0 - &fv[0][0]];
55 	pav1 = &av[pfv1 - &fv[0][0]];
56 
57 	if (pfv0->v[1] >= pfv1->v[1]) {
58 		scale = (ALIAS_Z_CLIP_PLANE - pav0->fv[2]) /
59 			(pav1->fv[2] - pav0->fv[2]);
60 
61 		avout.fv[0] = pav0->fv[0] + (pav1->fv[0] - pav0->fv[0]) * scale;
62 		avout.fv[1] = pav0->fv[1] + (pav1->fv[1] - pav0->fv[1]) * scale;
63 		avout.fv[2] = ALIAS_Z_CLIP_PLANE;
64 
65 		out->v[2] = pfv0->v[2] + (pfv1->v[2] - pfv0->v[2]) * scale;
66 		out->v[3] = pfv0->v[3] + (pfv1->v[3] - pfv0->v[3]) * scale;
67 		out->v[4] = pfv0->v[4] + (pfv1->v[4] - pfv0->v[4]) * scale;
68 	} else {
69 		scale = (ALIAS_Z_CLIP_PLANE - pav1->fv[2]) /
70 			(pav0->fv[2] - pav1->fv[2]);
71 
72 		avout.fv[0] = pav1->fv[0] + (pav0->fv[0] - pav1->fv[0]) * scale;
73 		avout.fv[1] = pav1->fv[1] + (pav0->fv[1] - pav1->fv[1]) * scale;
74 		avout.fv[2] = ALIAS_Z_CLIP_PLANE;
75 
76 		out->v[2] = pfv1->v[2] + (pfv0->v[2] - pfv1->v[2]) * scale;
77 		out->v[3] = pfv1->v[3] + (pfv0->v[3] - pfv1->v[3]) * scale;
78 		out->v[4] = pfv1->v[4] + (pfv0->v[4] - pfv1->v[4]) * scale;
79 	}
80 
81 	R_AliasProjectFinalVert (out, &avout);
82 
83 	if (out->v[0] < r_refdef.aliasvrect.x)
84 		out->flags |= ALIAS_LEFT_CLIP;
85 	if (out->v[1] < r_refdef.aliasvrect.y)
86 		out->flags |= ALIAS_TOP_CLIP;
87 	if (out->v[0] > r_refdef.aliasvrectright)
88 		out->flags |= ALIAS_RIGHT_CLIP;
89 	if (out->v[1] > r_refdef.aliasvrectbottom)
90 		out->flags |= ALIAS_BOTTOM_CLIP;
91 }
92 
93 #ifndef USE_INTEL_ASM
94 
95 void
R_Alias_clip_left(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out)96 R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
97 {
98 	float       scale;
99 	int         i;
100 
101 	if (pfv0->v[1] >= pfv1->v[1]) {
102 		scale = (float) (r_refdef.aliasvrect.x - pfv0->v[0]) /
103 			(pfv1->v[0] - pfv0->v[0]);
104 		for (i = 0; i < 6; i++)
105 			out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i]) * scale + 0.5;
106 	} else {
107 		scale = (float) (r_refdef.aliasvrect.x - pfv1->v[0]) /
108 			(pfv0->v[0] - pfv1->v[0]);
109 		for (i = 0; i < 6; i++)
110 			out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
111 	}
112 }
113 
114 
115 void
R_Alias_clip_right(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out)116 R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
117 {
118 	float       scale;
119 	int         i;
120 
121 	if (pfv0->v[1] >= pfv1->v[1]) {
122 		scale = (float) (r_refdef.aliasvrectright - pfv0->v[0]) /
123 			(pfv1->v[0] - pfv0->v[0]);
124 		for (i = 0; i < 6; i++)
125 			out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i]) * scale + 0.5;
126 	} else {
127 		scale = (float) (r_refdef.aliasvrectright - pfv1->v[0]) /
128 			(pfv0->v[0] - pfv1->v[0]);
129 		for (i = 0; i < 6; i++)
130 			out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
131 	}
132 }
133 
134 
135 void
R_Alias_clip_top(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out)136 R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
137 {
138 	float       scale;
139 	int         i;
140 
141 	if (pfv0->v[1] >= pfv1->v[1]) {
142 		scale = (float) (r_refdef.aliasvrect.y - pfv0->v[1]) /
143 			(pfv1->v[1] - pfv0->v[1]);
144 		for (i = 0; i < 6; i++)
145 			out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i]) * scale + 0.5;
146 	} else {
147 		scale = (float) (r_refdef.aliasvrect.y - pfv1->v[1]) /
148 			(pfv0->v[1] - pfv1->v[1]);
149 		for (i = 0; i < 6; i++)
150 			out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
151 	}
152 }
153 
154 
155 void
R_Alias_clip_bottom(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out)156 R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
157 {
158 	float       scale;
159 	int         i;
160 
161 	if (pfv0->v[1] >= pfv1->v[1]) {
162 		scale = (float) (r_refdef.aliasvrectbottom - pfv0->v[1]) /
163 			(pfv1->v[1] - pfv0->v[1]);
164 
165 		for (i = 0; i < 6; i++)
166 			out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i]) * scale + 0.5;
167 	} else {
168 		scale = (float) (r_refdef.aliasvrectbottom - pfv1->v[1]) /
169 			(pfv0->v[1] - pfv1->v[1]);
170 
171 		for (i = 0; i < 6; i++)
172 			out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
173 	}
174 }
175 
176 #endif
177 
178 
179 static int
R_AliasClip(finalvert_t * in,finalvert_t * out,int flag,int count,void (* clip)(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out))180 R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
181 			 void (*clip) (finalvert_t *pfv0, finalvert_t *pfv1,
182 						   finalvert_t *out))
183 {
184 	int         i, j, k;
185 	int         flags, oldflags;
186 
187 	j = count - 1;
188 	k = 0;
189 	for (i = 0; i < count; j = i, i++) {
190 		oldflags = in[j].flags & flag;
191 		flags = in[i].flags & flag;
192 
193 		if (flags && oldflags)
194 			continue;
195 		if (oldflags ^ flags) {
196 			clip (&in[j], &in[i], &out[k]);
197 			out[k].flags = 0;
198 			if (out[k].v[0] < r_refdef.aliasvrect.x)
199 				out[k].flags |= ALIAS_LEFT_CLIP;
200 			if (out[k].v[1] < r_refdef.aliasvrect.y)
201 				out[k].flags |= ALIAS_TOP_CLIP;
202 			if (out[k].v[0] > r_refdef.aliasvrectright)
203 				out[k].flags |= ALIAS_RIGHT_CLIP;
204 			if (out[k].v[1] > r_refdef.aliasvrectbottom)
205 				out[k].flags |= ALIAS_BOTTOM_CLIP;
206 			k++;
207 		}
208 		if (!flags) {
209 			out[k] = in[i];
210 			k++;
211 		}
212 	}
213 
214 	return k;
215 }
216 
217 
218 void
R_AliasClipTriangle(mtriangle_t * ptri)219 R_AliasClipTriangle (mtriangle_t *ptri)
220 {
221 	int         i, k, pingpong;
222 	mtriangle_t mtri;
223 	unsigned int clipflags;
224 
225 	// copy vertexes and fix seam texture coordinates
226 	if (ptri->facesfront) {
227 		fv[0][0] = pfinalverts[ptri->vertindex[0]];
228 		fv[0][1] = pfinalverts[ptri->vertindex[1]];
229 		fv[0][2] = pfinalverts[ptri->vertindex[2]];
230 	} else {
231 		for (i = 0; i < 3; i++) {
232 			fv[0][i] = pfinalverts[ptri->vertindex[i]];
233 
234 			if (!ptri->facesfront && (fv[0][i].flags & ALIAS_ONSEAM))
235 				fv[0][i].v[2] += r_affinetridesc.seamfixupX16;
236 		}
237 	}
238 
239 	// clip
240 	clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
241 
242 	if (clipflags & ALIAS_Z_CLIP) {
243 		for (i = 0; i < 3; i++)
244 			av[i] = pauxverts[ptri->vertindex[i]];
245 
246 		k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
247 		if (k == 0)
248 			return;
249 
250 		pingpong = 1;
251 		clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
252 	} else {
253 		pingpong = 0;
254 		k = 3;
255 	}
256 
257 	if (clipflags & ALIAS_LEFT_CLIP) {
258 		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
259 						 ALIAS_LEFT_CLIP, k, R_Alias_clip_left);
260 		if (k == 0)
261 			return;
262 
263 		pingpong ^= 1;
264 	}
265 
266 	if (clipflags & ALIAS_RIGHT_CLIP) {
267 		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
268 						 ALIAS_RIGHT_CLIP, k, R_Alias_clip_right);
269 		if (k == 0)
270 			return;
271 
272 		pingpong ^= 1;
273 	}
274 
275 	if (clipflags & ALIAS_BOTTOM_CLIP) {
276 		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
277 						 ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom);
278 		if (k == 0)
279 			return;
280 
281 		pingpong ^= 1;
282 	}
283 
284 	if (clipflags & ALIAS_TOP_CLIP) {
285 		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
286 						 ALIAS_TOP_CLIP, k, R_Alias_clip_top);
287 		if (k == 0)
288 			return;
289 
290 		pingpong ^= 1;
291 	}
292 
293 	for (i = 0; i < k; i++) {
294 		if (fv[pingpong][i].v[0] < r_refdef.aliasvrect.x)
295 			fv[pingpong][i].v[0] = r_refdef.aliasvrect.x;
296 		else if (fv[pingpong][i].v[0] > r_refdef.aliasvrectright)
297 			fv[pingpong][i].v[0] = r_refdef.aliasvrectright;
298 
299 		if (fv[pingpong][i].v[1] < r_refdef.aliasvrect.y)
300 			fv[pingpong][i].v[1] = r_refdef.aliasvrect.y;
301 		else if (fv[pingpong][i].v[1] > r_refdef.aliasvrectbottom)
302 			fv[pingpong][i].v[1] = r_refdef.aliasvrectbottom;
303 
304 		fv[pingpong][i].flags = 0;
305 	}
306 
307 	// draw triangles
308 	mtri.facesfront = ptri->facesfront;
309 	r_affinetridesc.ptriangles = &mtri;
310 	r_affinetridesc.pfinalverts = fv[pingpong];
311 
312 	// FIXME: do all at once as trifan?
313 	mtri.vertindex[0] = 0;
314 	for (i = 1; i < k - 1; i++) {
315 		mtri.vertindex[1] = i;
316 		mtri.vertindex[2] = i + 1;
317 		D_PolysetDraw ();
318 	}
319 }
320