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 #define NH_DEFINE
32 #include "namehack.h"
33 
34 #include "QF/render.h"
35 
36 #include "d_local.h"
37 #include "r_internal.h"
38 
39 static finalvert_t fv[2][8];
40 static auxvert_t av[8];
41 
42 /*
43 	R_Alias_clip_z
44 
45 	pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
46 */
47 static void
R_Alias_clip_z(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out)48 R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
49 {
50 	float       scale;
51 	auxvert_t  *pav0, *pav1, avout;
52 
53 	pav0 = &av[pfv0 - &fv[0][0]];
54 	pav1 = &av[pfv1 - &fv[0][0]];
55 
56 	if (pfv0->v[1] >= pfv1->v[1]) {
57 		scale = (ALIAS_Z_CLIP_PLANE - pav0->fv[2]) /
58 			(pav1->fv[2] - pav0->fv[2]);
59 
60 		avout.fv[0] = pav0->fv[0] + (pav1->fv[0] - pav0->fv[0]) * scale;
61 		avout.fv[1] = pav0->fv[1] + (pav1->fv[1] - pav0->fv[1]) * scale;
62 		avout.fv[2] = ALIAS_Z_CLIP_PLANE;
63 
64 		out->v[2] = pfv0->v[2] + (pfv1->v[2] - pfv0->v[2]) * scale;
65 		out->v[3] = pfv0->v[3] + (pfv1->v[3] - pfv0->v[3]) * scale;
66 		out->v[4] = pfv0->v[4] + (pfv1->v[4] - pfv0->v[4]) * scale;
67 	} else {
68 		scale = (ALIAS_Z_CLIP_PLANE - pav1->fv[2]) /
69 			(pav0->fv[2] - pav1->fv[2]);
70 
71 		avout.fv[0] = pav1->fv[0] + (pav0->fv[0] - pav1->fv[0]) * scale;
72 		avout.fv[1] = pav1->fv[1] + (pav0->fv[1] - pav1->fv[1]) * scale;
73 		avout.fv[2] = ALIAS_Z_CLIP_PLANE;
74 
75 		out->v[2] = pfv1->v[2] + (pfv0->v[2] - pfv1->v[2]) * scale;
76 		out->v[3] = pfv1->v[3] + (pfv0->v[3] - pfv1->v[3]) * scale;
77 		out->v[4] = pfv1->v[4] + (pfv0->v[4] - pfv1->v[4]) * scale;
78 	}
79 
80 	sw32_R_AliasProjectFinalVert (out, &avout);
81 
82 	if (out->v[0] < r_refdef.aliasvrect.x)
83 		out->flags |= ALIAS_LEFT_CLIP;
84 	if (out->v[1] < r_refdef.aliasvrect.y)
85 		out->flags |= ALIAS_TOP_CLIP;
86 	if (out->v[0] > r_refdef.aliasvrectright)
87 		out->flags |= ALIAS_RIGHT_CLIP;
88 	if (out->v[1] > r_refdef.aliasvrectbottom)
89 		out->flags |= ALIAS_BOTTOM_CLIP;
90 }
91 
92 
93 void
sw32_R_Alias_clip_left(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out)94 sw32_R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
95 {
96 	float       scale;
97 	int         i;
98 
99 	if (pfv0->v[1] >= pfv1->v[1]) {
100 		scale = (float) (r_refdef.aliasvrect.x - pfv0->v[0]) /
101 			(pfv1->v[0] - pfv0->v[0]);
102 		for (i = 0; i < 6; i++)
103 			out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i]) * scale + 0.5;
104 	} else {
105 		scale = (float) (r_refdef.aliasvrect.x - pfv1->v[0]) /
106 			(pfv0->v[0] - pfv1->v[0]);
107 		for (i = 0; i < 6; i++)
108 			out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
109 	}
110 }
111 
112 
113 void
sw32_R_Alias_clip_right(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out)114 sw32_R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
115 {
116 	float       scale;
117 	int         i;
118 
119 	if (pfv0->v[1] >= pfv1->v[1]) {
120 		scale = (float) (r_refdef.aliasvrectright - pfv0->v[0]) /
121 			(pfv1->v[0] - pfv0->v[0]);
122 		for (i = 0; i < 6; i++)
123 			out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i]) * scale + 0.5;
124 	} else {
125 		scale = (float) (r_refdef.aliasvrectright - pfv1->v[0]) /
126 			(pfv0->v[0] - pfv1->v[0]);
127 		for (i = 0; i < 6; i++)
128 			out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
129 	}
130 }
131 
132 
133 void
sw32_R_Alias_clip_top(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out)134 sw32_R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
135 {
136 	float       scale;
137 	int         i;
138 
139 	if (pfv0->v[1] >= pfv1->v[1]) {
140 		scale = (float) (r_refdef.aliasvrect.y - pfv0->v[1]) /
141 			(pfv1->v[1] - pfv0->v[1]);
142 		for (i = 0; i < 6; i++)
143 			out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i]) * scale + 0.5;
144 	} else {
145 		scale = (float) (r_refdef.aliasvrect.y - pfv1->v[1]) /
146 			(pfv0->v[1] - pfv1->v[1]);
147 		for (i = 0; i < 6; i++)
148 			out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
149 	}
150 }
151 
152 
153 void
sw32_R_Alias_clip_bottom(finalvert_t * pfv0,finalvert_t * pfv1,finalvert_t * out)154 sw32_R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
155 {
156 	float       scale;
157 	int         i;
158 
159 	if (pfv0->v[1] >= pfv1->v[1]) {
160 		scale = (float) (r_refdef.aliasvrectbottom - pfv0->v[1]) /
161 			(pfv1->v[1] - pfv0->v[1]);
162 
163 		for (i = 0; i < 6; i++)
164 			out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i]) * scale + 0.5;
165 	} else {
166 		scale = (float) (r_refdef.aliasvrectbottom - pfv1->v[1]) /
167 			(pfv0->v[1] - pfv1->v[1]);
168 
169 		for (i = 0; i < 6; i++)
170 			out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i]) * scale + 0.5;
171 	}
172 }
173 
174 
175 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))176 R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
177 			 void (*clip) (finalvert_t *pfv0, finalvert_t *pfv1,
178 						   finalvert_t *out))
179 {
180 	int         i, j, k;
181 	int         flags, oldflags;
182 
183 	j = count - 1;
184 	k = 0;
185 	for (i = 0; i < count; j = i, i++) {
186 		oldflags = in[j].flags & flag;
187 		flags = in[i].flags & flag;
188 
189 		if (flags && oldflags)
190 			continue;
191 		if (oldflags ^ flags) {
192 			clip (&in[j], &in[i], &out[k]);
193 			out[k].flags = 0;
194 			if (out[k].v[0] < r_refdef.aliasvrect.x)
195 				out[k].flags |= ALIAS_LEFT_CLIP;
196 			if (out[k].v[1] < r_refdef.aliasvrect.y)
197 				out[k].flags |= ALIAS_TOP_CLIP;
198 			if (out[k].v[0] > r_refdef.aliasvrectright)
199 				out[k].flags |= ALIAS_RIGHT_CLIP;
200 			if (out[k].v[1] > r_refdef.aliasvrectbottom)
201 				out[k].flags |= ALIAS_BOTTOM_CLIP;
202 			k++;
203 		}
204 		if (!flags) {
205 			out[k] = in[i];
206 			k++;
207 		}
208 	}
209 
210 	return k;
211 }
212 
213 
214 void
sw32_R_AliasClipTriangle(mtriangle_t * ptri)215 sw32_R_AliasClipTriangle (mtriangle_t *ptri)
216 {
217 	int         i, k, pingpong;
218 	mtriangle_t mtri;
219 	unsigned int clipflags;
220 
221 	// copy vertexes and fix seam texture coordinates
222 	if (ptri->facesfront) {
223 		fv[0][0] = pfinalverts[ptri->vertindex[0]];
224 		fv[0][1] = pfinalverts[ptri->vertindex[1]];
225 		fv[0][2] = pfinalverts[ptri->vertindex[2]];
226 	} else {
227 		for (i = 0; i < 3; i++) {
228 			fv[0][i] = pfinalverts[ptri->vertindex[i]];
229 
230 			if (!ptri->facesfront && (fv[0][i].flags & ALIAS_ONSEAM))
231 				fv[0][i].v[2] += sw32_r_affinetridesc.seamfixupX16;
232 		}
233 	}
234 
235 	// clip
236 	clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
237 
238 	if (clipflags & ALIAS_Z_CLIP) {
239 		for (i = 0; i < 3; i++)
240 			av[i] = sw32_pauxverts[ptri->vertindex[i]];
241 
242 		k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
243 		if (k == 0)
244 			return;
245 
246 		pingpong = 1;
247 		clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
248 	} else {
249 		pingpong = 0;
250 		k = 3;
251 	}
252 
253 	if (clipflags & ALIAS_LEFT_CLIP) {
254 		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
255 						 ALIAS_LEFT_CLIP, k, sw32_R_Alias_clip_left);
256 		if (k == 0)
257 			return;
258 
259 		pingpong ^= 1;
260 	}
261 
262 	if (clipflags & ALIAS_RIGHT_CLIP) {
263 		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
264 						 ALIAS_RIGHT_CLIP, k, sw32_R_Alias_clip_right);
265 		if (k == 0)
266 			return;
267 
268 		pingpong ^= 1;
269 	}
270 
271 	if (clipflags & ALIAS_BOTTOM_CLIP) {
272 		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
273 						 ALIAS_BOTTOM_CLIP, k, sw32_R_Alias_clip_bottom);
274 		if (k == 0)
275 			return;
276 
277 		pingpong ^= 1;
278 	}
279 
280 	if (clipflags & ALIAS_TOP_CLIP) {
281 		k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
282 						 ALIAS_TOP_CLIP, k, sw32_R_Alias_clip_top);
283 		if (k == 0)
284 			return;
285 
286 		pingpong ^= 1;
287 	}
288 
289 	for (i = 0; i < k; i++) {
290 		if (fv[pingpong][i].v[0] < r_refdef.aliasvrect.x)
291 			fv[pingpong][i].v[0] = r_refdef.aliasvrect.x;
292 		else if (fv[pingpong][i].v[0] > r_refdef.aliasvrectright)
293 			fv[pingpong][i].v[0] = r_refdef.aliasvrectright;
294 
295 		if (fv[pingpong][i].v[1] < r_refdef.aliasvrect.y)
296 			fv[pingpong][i].v[1] = r_refdef.aliasvrect.y;
297 		else if (fv[pingpong][i].v[1] > r_refdef.aliasvrectbottom)
298 			fv[pingpong][i].v[1] = r_refdef.aliasvrectbottom;
299 
300 		fv[pingpong][i].flags = 0;
301 	}
302 
303 	// draw triangles
304 	mtri.facesfront = ptri->facesfront;
305 	sw32_r_affinetridesc.ptriangles = &mtri;
306 	sw32_r_affinetridesc.pfinalverts = fv[pingpong];
307 
308 	// FIXME: do all at once as trifan?
309 	mtri.vertindex[0] = 0;
310 	for (i = 1; i < k - 1; i++) {
311 		mtri.vertindex[1] = i;
312 		mtri.vertindex[2] = i + 1;
313 		sw32_D_PolysetDraw ();
314 	}
315 }
316