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