Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 1
/*
2
Copyright (C) 1996-1997 Id Software, Inc.
3
 
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License
6
as published by the Free Software Foundation; either version 2
7
of the License, or (at your option) any later version.
8
 
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
 
13
See the GNU General Public License for more details.
14
 
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
 
19
*/
20
 
21
// r_draw.c
22
 
23
#include "quakedef.h"
24
#include "r_local.h"
25
#include "d_local.h"	// FIXME: shouldn't need to include this
26
 
27
#define MAXLEFTCLIPEDGES		100
28
 
29
// !!! if these are changed, they must be changed in asm_draw.h too !!!
30
#define FULLY_CLIPPED_CACHED	0x80000000
31
#define FRAMECOUNT_MASK			0x7FFFFFFF
32
 
33
unsigned int	cacheoffset;
34
 
35
int			c_faceclip;					// number of faces clipped
36
 
37
zpointdesc_t	r_zpointdesc;
38
 
39
polydesc_t		r_polydesc;
40
 
41
 
42
 
43
clipplane_t	*entity_clipplanes;
44
clipplane_t	view_clipplanes[4];
45
clipplane_t	world_clipplanes[16];
46
 
47
medge_t			*r_pedge;
48
 
49
qboolean		r_leftclipped, r_rightclipped;
50
static qboolean	makeleftedge, makerightedge;
51
qboolean		r_nearzionly;
52
 
53
int		sintable[SIN_BUFFER_SIZE];
54
int		intsintable[SIN_BUFFER_SIZE];
55
 
56
mvertex_t	r_leftenter, r_leftexit;
57
mvertex_t	r_rightenter, r_rightexit;
58
 
59
typedef struct
60
{
61
	float	u,v;
62
	int		ceilv;
63
} evert_t;
64
 
65
int				r_emitted;
66
float			r_nearzi;
67
float			r_u1, r_v1, r_lzi1;
68
int				r_ceilv1;
69
 
70
qboolean	r_lastvertvalid;
71
 
72
 
73
#if	!id386
74
 
75
/*
76
================
77
R_EmitEdge
78
================
79
*/
80
void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
81
{
82
	edge_t	*edge, *pcheck;
83
	int		u_check;
84
	float	u, u_step;
85
	vec3_t	local, transformed;
86
	float	*world;
87
	int		v, v2, ceilv0;
88
	float	scale, lzi0, u0, v0;
89
	int		side;
90
 
91
	if (r_lastvertvalid)
92
	{
93
		u0 = r_u1;
94
		v0 = r_v1;
95
		lzi0 = r_lzi1;
96
		ceilv0 = r_ceilv1;
97
	}
98
	else
99
	{
100
		world = &pv0->position[0];
101
 
102
	// transform and project
103
		VectorSubtract (world, modelorg, local);
104
		TransformVector (local, transformed);
105
 
106
		if (transformed[2] < NEAR_CLIP)
107
			transformed[2] = NEAR_CLIP;
108
 
109
		lzi0 = 1.0 / transformed[2];
110
 
111
	// FIXME: build x/yscale into transform?
112
		scale = xscale * lzi0;
113
		u0 = (xcenter + scale*transformed[0]);
114
		if (u0 < r_refdef.fvrectx_adj)
115
			u0 = r_refdef.fvrectx_adj;
116
		if (u0 > r_refdef.fvrectright_adj)
117
			u0 = r_refdef.fvrectright_adj;
118
 
119
		scale = yscale * lzi0;
120
		v0 = (ycenter - scale*transformed[1]);
121
		if (v0 < r_refdef.fvrecty_adj)
122
			v0 = r_refdef.fvrecty_adj;
123
		if (v0 > r_refdef.fvrectbottom_adj)
124
			v0 = r_refdef.fvrectbottom_adj;
125
 
126
		ceilv0 = (int) ceil(v0);
127
	}
128
 
129
	world = &pv1->position[0];
130
 
131
// transform and project
132
	VectorSubtract (world, modelorg, local);
133
	TransformVector (local, transformed);
134
 
135
	if (transformed[2] < NEAR_CLIP)
136
		transformed[2] = NEAR_CLIP;
137
 
138
	r_lzi1 = 1.0 / transformed[2];
139
 
140
	scale = xscale * r_lzi1;
141
	r_u1 = (xcenter + scale*transformed[0]);
142
	if (r_u1 < r_refdef.fvrectx_adj)
143
		r_u1 = r_refdef.fvrectx_adj;
144
	if (r_u1 > r_refdef.fvrectright_adj)
145
		r_u1 = r_refdef.fvrectright_adj;
146
 
147
	scale = yscale * r_lzi1;
148
	r_v1 = (ycenter - scale*transformed[1]);
149
	if (r_v1 < r_refdef.fvrecty_adj)
150
		r_v1 = r_refdef.fvrecty_adj;
151
	if (r_v1 > r_refdef.fvrectbottom_adj)
152
		r_v1 = r_refdef.fvrectbottom_adj;
153
 
154
	if (r_lzi1 > lzi0)
155
		lzi0 = r_lzi1;
156
 
157
	if (lzi0 > r_nearzi)	// for mipmap finding
158
		r_nearzi = lzi0;
159
 
160
// for right edges, all we want is the effect on 1/z
161
	if (r_nearzionly)
162
		return;
163
 
164
	r_emitted = 1;
165
 
166
	r_ceilv1 = (int) ceil(r_v1);
167
 
168
 
169
// create the edge
170
	if (ceilv0 == r_ceilv1)
171
	{
172
	// we cache unclipped horizontal edges as fully clipped
173
		if (cacheoffset != 0x7FFFFFFF)
174
		{
175
			cacheoffset = FULLY_CLIPPED_CACHED |
176
					(r_framecount & FRAMECOUNT_MASK);
177
		}
178
 
179
		return;		// horizontal edge
180
	}
181
 
182
	side = ceilv0 > r_ceilv1;
183
 
184
	edge = edge_p++;
185
 
186
	edge->owner = r_pedge;
187
 
188
	edge->nearzi = lzi0;
189
 
190
	if (side == 0)
191
	{
192
	// trailing edge (go from p1 to p2)
193
		v = ceilv0;
194
		v2 = r_ceilv1 - 1;
195
 
196
		edge->surfs[0] = surface_p - surfaces;
197
		edge->surfs[1] = 0;
198
 
199
		u_step = ((r_u1 - u0) / (r_v1 - v0));
200
		u = u0 + ((float)v - v0) * u_step;
201
	}
202
	else
203
	{
204
	// leading edge (go from p2 to p1)
205
		v2 = ceilv0 - 1;
206
		v = r_ceilv1;
207
 
208
		edge->surfs[0] = 0;
209
		edge->surfs[1] = surface_p - surfaces;
210
 
211
		u_step = ((u0 - r_u1) / (v0 - r_v1));
212
		u = r_u1 + ((float)v - r_v1) * u_step;
213
	}
214
 
215
	edge->u_step = u_step*0x100000;
216
	edge->u = u*0x100000 + 0xFFFFF;
217
 
218
// we need to do this to avoid stepping off the edges if a very nearly
219
// horizontal edge is less than epsilon above a scan, and numeric error causes
220
// it to incorrectly extend to the scan, and the extension of the line goes off
221
// the edge of the screen
222
// FIXME: is this actually needed?
223
	if (edge->u < r_refdef.vrect_x_adj_shift20)
224
		edge->u = r_refdef.vrect_x_adj_shift20;
225
	if (edge->u > r_refdef.vrectright_adj_shift20)
226
		edge->u = r_refdef.vrectright_adj_shift20;
227
 
228
//
229
// sort the edge in normally
230
//
231
	u_check = edge->u;
232
	if (edge->surfs[0])
233
		u_check++;	// sort trailers after leaders
234
 
235
	if (!newedges[v] || newedges[v]->u >= u_check)
236
	{
237
		edge->next = newedges[v];
238
		newedges[v] = edge;
239
	}
240
	else
241
	{
242
		pcheck = newedges[v];
243
		while (pcheck->next && pcheck->next->u < u_check)
244
			pcheck = pcheck->next;
245
		edge->next = pcheck->next;
246
		pcheck->next = edge;
247
	}
248
 
249
	edge->nextremove = removeedges[v2];
250
	removeedges[v2] = edge;
251
}
252
 
253
 
254
/*
255
================
256
R_ClipEdge
257
================
258
*/
259
void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
260
{
261
	float		d0, d1, f;
262
	mvertex_t	clipvert;
263
 
264
	if (clip)
265
	{
266
		do
267
		{
268
			d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
269
			d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
270
 
271
			if (d0 >= 0)
272
			{
273
			// point 0 is unclipped
274
				if (d1 >= 0)
275
				{
276
				// both points are unclipped
277
					continue;
278
				}
279
 
280
			// only point 1 is clipped
281
 
282
			// we don't cache clipped edges
283
				cacheoffset = 0x7FFFFFFF;
284
 
285
				f = d0 / (d0 - d1);
286
				clipvert.position[0] = pv0->position[0] +
287
						f * (pv1->position[0] - pv0->position[0]);
288
				clipvert.position[1] = pv0->position[1] +
289
						f * (pv1->position[1] - pv0->position[1]);
290
				clipvert.position[2] = pv0->position[2] +
291
						f * (pv1->position[2] - pv0->position[2]);
292
 
293
				if (clip->leftedge)
294
				{
295
					r_leftclipped = true;
296
					r_leftexit = clipvert;
297
				}
298
				else if (clip->rightedge)
299
				{
300
					r_rightclipped = true;
301
					r_rightexit = clipvert;
302
				}
303
 
304
				R_ClipEdge (pv0, &clipvert, clip->next);
305
				return;
306
			}
307
			else
308
			{
309
			// point 0 is clipped
310
				if (d1 < 0)
311
				{
312
				// both points are clipped
313
				// we do cache fully clipped edges
314
					if (!r_leftclipped)
315
						cacheoffset = FULLY_CLIPPED_CACHED |
316
								(r_framecount & FRAMECOUNT_MASK);
317
					return;
318
				}
319
 
320
			// only point 0 is clipped
321
				r_lastvertvalid = false;
322
 
323
			// we don't cache partially clipped edges
324
				cacheoffset = 0x7FFFFFFF;
325
 
326
				f = d0 / (d0 - d1);
327
				clipvert.position[0] = pv0->position[0] +
328
						f * (pv1->position[0] - pv0->position[0]);
329
				clipvert.position[1] = pv0->position[1] +
330
						f * (pv1->position[1] - pv0->position[1]);
331
				clipvert.position[2] = pv0->position[2] +
332
						f * (pv1->position[2] - pv0->position[2]);
333
 
334
				if (clip->leftedge)
335
				{
336
					r_leftclipped = true;
337
					r_leftenter = clipvert;
338
				}
339
				else if (clip->rightedge)
340
				{
341
					r_rightclipped = true;
342
					r_rightenter = clipvert;
343
				}
344
 
345
				R_ClipEdge (&clipvert, pv1, clip->next);
346
				return;
347
			}
348
		} while ((clip = clip->next) != NULL);
349
	}
350
 
351
// add the edge
352
	R_EmitEdge (pv0, pv1);
353
}
354
 
355
#endif	// !id386
356
 
357
 
358
/*
359
================
360
R_EmitCachedEdge
361
================
362
*/
363
void R_EmitCachedEdge (void)
364
{
365
	edge_t		*pedge_t;
366
 
367
	pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset);
368
 
369
	if (!pedge_t->surfs[0])
370
		pedge_t->surfs[0] = surface_p - surfaces;
371
	else
372
		pedge_t->surfs[1] = surface_p - surfaces;
373
 
374
	if (pedge_t->nearzi > r_nearzi)	// for mipmap finding
375
		r_nearzi = pedge_t->nearzi;
376
 
377
	r_emitted = 1;
378
}
379
 
380
 
381
/*
382
================
383
R_RenderFace
384
================
385
*/
386
void R_RenderFace (msurface_t *fa, int clipflags)
387
{
388
	int			i, lindex;
389
	unsigned	mask;
390
	mplane_t	*pplane;
391
	float		distinv;
392
	vec3_t		p_normal;
393
	medge_t		*pedges, tedge;
394
	clipplane_t	*pclip;
395
 
396
// skip out if no more surfs
397
	if ((surface_p) >= surf_max)
398
	{
399
		r_outofsurfaces++;
400
		return;
401
	}
402
 
403
// ditto if not enough edges left, or switch to auxedges if possible
404
	if ((edge_p + fa->numedges + 4) >= edge_max)
405
	{
406
		r_outofedges += fa->numedges;
407
		return;
408
	}
409
 
410
	c_faceclip++;
411
 
412
// set up clip planes
413
	pclip = NULL;
414
 
415
	for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
416
	{
417
		if (clipflags & mask)
418
		{
419
			view_clipplanes[i].next = pclip;
420
			pclip = &view_clipplanes[i];
421
		}
422
	}
423
 
424
// push the edges through
425
	r_emitted = 0;
426
	r_nearzi = 0;
427
	r_nearzionly = false;
428
	makeleftedge = makerightedge = false;
429
	pedges = currententity->model->edges;
430
	r_lastvertvalid = false;
431
 
432
	for (i=0 ; inumedges ; i++)
433
	{
434
		lindex = currententity->model->surfedges[fa->firstedge + i];
435
 
436
		if (lindex > 0)
437
		{
438
			r_pedge = &pedges[lindex];
439
 
440
		// if the edge is cached, we can just reuse the edge
441
			if (!insubmodel)
442
			{
443
				if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
444
				{
445
					if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
446
						r_framecount)
447
					{
448
						r_lastvertvalid = false;
449
						continue;
450
					}
451
				}
452
				else
453
				{
454
					if ((((unsigned long)edge_p - (unsigned long)r_edges) >
455
						 r_pedge->cachededgeoffset) &&
456
						(((edge_t *)((unsigned long)r_edges +
457
						 r_pedge->cachededgeoffset))->owner == r_pedge))
458
					{
459
						R_EmitCachedEdge ();
460
						r_lastvertvalid = false;
461
						continue;
462
					}
463
				}
464
			}
465
 
466
		// assume it's cacheable
467
			cacheoffset = (byte *)edge_p - (byte *)r_edges;
468
			r_leftclipped = r_rightclipped = false;
469
			R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
470
						&r_pcurrentvertbase[r_pedge->v[1]],
471
						pclip);
472
			r_pedge->cachededgeoffset = cacheoffset;
473
 
474
			if (r_leftclipped)
475
				makeleftedge = true;
476
			if (r_rightclipped)
477
				makerightedge = true;
478
			r_lastvertvalid = true;
479
		}
480
		else
481
		{
482
			lindex = -lindex;
483
			r_pedge = &pedges[lindex];
484
		// if the edge is cached, we can just reuse the edge
485
			if (!insubmodel)
486
			{
487
				if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
488
				{
489
					if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
490
						r_framecount)
491
					{
492
						r_lastvertvalid = false;
493
						continue;
494
					}
495
				}
496
				else
497
				{
498
				// it's cached if the cached edge is valid and is owned
499
				// by this medge_t
500
					if ((((unsigned long)edge_p - (unsigned long)r_edges) >
501
						 r_pedge->cachededgeoffset) &&
502
						(((edge_t *)((unsigned long)r_edges +
503
						 r_pedge->cachededgeoffset))->owner == r_pedge))
504
					{
505
						R_EmitCachedEdge ();
506
						r_lastvertvalid = false;
507
						continue;
508
					}
509
				}
510
			}
511
 
512
		// assume it's cacheable
513
			cacheoffset = (byte *)edge_p - (byte *)r_edges;
514
			r_leftclipped = r_rightclipped = false;
515
			R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
516
						&r_pcurrentvertbase[r_pedge->v[0]],
517
						pclip);
518
			r_pedge->cachededgeoffset = cacheoffset;
519
 
520
			if (r_leftclipped)
521
				makeleftedge = true;
522
			if (r_rightclipped)
523
				makerightedge = true;
524
			r_lastvertvalid = true;
525
		}
526
	}
527
 
528
// if there was a clip off the left edge, add that edge too
529
// FIXME: faster to do in screen space?
530
// FIXME: share clipped edges?
531
	if (makeleftedge)
532
	{
533
		r_pedge = &tedge;
534
		r_lastvertvalid = false;
535
		R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
536
	}
537
 
538
// if there was a clip off the right edge, get the right r_nearzi
539
	if (makerightedge)
540
	{
541
		r_pedge = &tedge;
542
		r_lastvertvalid = false;
543
		r_nearzionly = true;
544
		R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
545
	}
546
 
547
// if no edges made it out, return without posting the surface
548
	if (!r_emitted)
549
		return;
550
 
551
	r_polycount++;
552
 
553
	surface_p->data = (void *)fa;
554
	surface_p->nearzi = r_nearzi;
555
	surface_p->flags = fa->flags;
556
	surface_p->insubmodel = insubmodel;
557
	surface_p->spanstate = 0;
558
	surface_p->entity = currententity;
559
	surface_p->key = r_currentkey++;
560
	surface_p->spans = NULL;
561
 
562
	pplane = fa->plane;
563
// FIXME: cache this?
564
	TransformVector (pplane->normal, p_normal);
565
// FIXME: cache this?
566
	distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
567
 
568
	surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
569
	surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
570
	surface_p->d_ziorigin = p_normal[2] * distinv -
571
			xcenter * surface_p->d_zistepu -
572
			ycenter * surface_p->d_zistepv;
573
 
574
//JDC	VectorCopy (r_worldmodelorg, surface_p->modelorg);
575
	surface_p++;
576
}
577
 
578
 
579
/*
580
================
581
R_RenderBmodelFace
582
================
583
*/
584
void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
585
{
586
	int			i;
587
	unsigned	mask;
588
	mplane_t	*pplane;
589
	float		distinv;
590
	vec3_t		p_normal;
591
	medge_t		tedge;
592
	clipplane_t	*pclip;
593
 
594
// skip out if no more surfs
595
	if (surface_p >= surf_max)
596
	{
597
		r_outofsurfaces++;
598
		return;
599
	}
600
 
601
// ditto if not enough edges left, or switch to auxedges if possible
602
	if ((edge_p + psurf->numedges + 4) >= edge_max)
603
	{
604
		r_outofedges += psurf->numedges;
605
		return;
606
	}
607
 
608
	c_faceclip++;
609
 
610
// this is a dummy to give the caching mechanism someplace to write to
611
	r_pedge = &tedge;
612
 
613
// set up clip planes
614
	pclip = NULL;
615
 
616
	for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
617
	{
618
		if (r_clipflags & mask)
619
		{
620
			view_clipplanes[i].next = pclip;
621
			pclip = &view_clipplanes[i];
622
		}
623
	}
624
 
625
// push the edges through
626
	r_emitted = 0;
627
	r_nearzi = 0;
628
	r_nearzionly = false;
629
	makeleftedge = makerightedge = false;
630
// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
631
// can be used?
632
	r_lastvertvalid = false;
633
 
634
	for ( ; pedges ; pedges = pedges->pnext)
635
	{
636
		r_leftclipped = r_rightclipped = false;
637
		R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
638
 
639
		if (r_leftclipped)
640
			makeleftedge = true;
641
		if (r_rightclipped)
642
			makerightedge = true;
643
	}
644
 
645
// if there was a clip off the left edge, add that edge too
646
// FIXME: faster to do in screen space?
647
// FIXME: share clipped edges?
648
	if (makeleftedge)
649
	{
650
		r_pedge = &tedge;
651
		R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
652
	}
653
 
654
// if there was a clip off the right edge, get the right r_nearzi
655
	if (makerightedge)
656
	{
657
		r_pedge = &tedge;
658
		r_nearzionly = true;
659
		R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
660
	}
661
 
662
// if no edges made it out, return without posting the surface
663
	if (!r_emitted)
664
		return;
665
 
666
	r_polycount++;
667
 
668
	surface_p->data = (void *)psurf;
669
	surface_p->nearzi = r_nearzi;
670
	surface_p->flags = psurf->flags;
671
	surface_p->insubmodel = true;
672
	surface_p->spanstate = 0;
673
	surface_p->entity = currententity;
674
	surface_p->key = r_currentbkey;
675
	surface_p->spans = NULL;
676
 
677
	pplane = psurf->plane;
678
// FIXME: cache this?
679
	TransformVector (pplane->normal, p_normal);
680
// FIXME: cache this?
681
	distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
682
 
683
	surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
684
	surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
685
	surface_p->d_ziorigin = p_normal[2] * distinv -
686
			xcenter * surface_p->d_zistepu -
687
			ycenter * surface_p->d_zistepv;
688
 
689
//JDC	VectorCopy (r_worldmodelorg, surface_p->modelorg);
690
	surface_p++;
691
}
692
 
693
 
694
/*
695
================
696
R_RenderPoly
697
================
698
*/
699
void R_RenderPoly (msurface_t *fa, int clipflags)
700
{
701
	int			i, lindex, lnumverts, s_axis, t_axis;
702
	float		dist, lastdist, lzi, scale, u, v, frac;
703
	unsigned	mask;
704
	vec3_t		local, transformed;
705
	clipplane_t	*pclip;
706
	medge_t		*pedges;
707
	mplane_t	*pplane;
708
	mvertex_t	verts[2][100];	//FIXME: do real number
709
	polyvert_t	pverts[100];	//FIXME: do real number, safely
710
	int			vertpage, newverts, newpage, lastvert;
711
	qboolean	visible;
712
 
713
// FIXME: clean this up and make it faster
714
// FIXME: guard against running out of vertices
715
 
716
	s_axis = t_axis = 0;	// keep compiler happy
717
 
718
// set up clip planes
719
	pclip = NULL;
720
 
721
	for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
722
	{
723
		if (clipflags & mask)
724
		{
725
			view_clipplanes[i].next = pclip;
726
			pclip = &view_clipplanes[i];
727
		}
728
	}
729
 
730
// reconstruct the polygon
731
// FIXME: these should be precalculated and loaded off disk
732
	pedges = currententity->model->edges;
733
	lnumverts = fa->numedges;
734
	vertpage = 0;
735
 
736
	for (i=0 ; i
737
	{
738
		lindex = currententity->model->surfedges[fa->firstedge + i];
739
 
740
		if (lindex > 0)
741
		{
742
			r_pedge = &pedges[lindex];
743
			verts[0][i] = r_pcurrentvertbase[r_pedge->v[0]];
744
		}
745
		else
746
		{
747
			r_pedge = &pedges[-lindex];
748
			verts[0][i] = r_pcurrentvertbase[r_pedge->v[1]];
749
		}
750
	}
751
 
752
// clip the polygon, done if not visible
753
	while (pclip)
754
	{
755
		lastvert = lnumverts - 1;
756
		lastdist = DotProduct (verts[vertpage][lastvert].position,
757
							   pclip->normal) - pclip->dist;
758
 
759
		visible = false;
760
		newverts = 0;
761
		newpage = vertpage ^ 1;
762
 
763
		for (i=0 ; i
764
		{
765
			dist = DotProduct (verts[vertpage][i].position, pclip->normal) -
766
					pclip->dist;
767
 
768
			if ((lastdist > 0) != (dist > 0))
769
			{
770
				frac = dist / (dist - lastdist);
771
				verts[newpage][newverts].position[0] =
772
						verts[vertpage][i].position[0] +
773
						((verts[vertpage][lastvert].position[0] -
774
						  verts[vertpage][i].position[0]) * frac);
775
				verts[newpage][newverts].position[1] =
776
						verts[vertpage][i].position[1] +
777
						((verts[vertpage][lastvert].position[1] -
778
						  verts[vertpage][i].position[1]) * frac);
779
				verts[newpage][newverts].position[2] =
780
						verts[vertpage][i].position[2] +
781
						((verts[vertpage][lastvert].position[2] -
782
						  verts[vertpage][i].position[2]) * frac);
783
				newverts++;
784
			}
785
 
786
			if (dist >= 0)
787
			{
788
				verts[newpage][newverts] = verts[vertpage][i];
789
				newverts++;
790
				visible = true;
791
			}
792
 
793
			lastvert = i;
794
			lastdist = dist;
795
		}
796
 
797
		if (!visible || (newverts < 3))
798
			return;
799
 
800
		lnumverts = newverts;
801
		vertpage ^= 1;
802
		pclip = pclip->next;
803
	}
804
 
805
// transform and project, remembering the z values at the vertices and
806
// r_nearzi, and extract the s and t coordinates at the vertices
807
	pplane = fa->plane;
808
	switch (pplane->type)
809
	{
810
	case PLANE_X:
811
	case PLANE_ANYX:
812
		s_axis = 1;
813
		t_axis = 2;
814
		break;
815
	case PLANE_Y:
816
	case PLANE_ANYY:
817
		s_axis = 0;
818
		t_axis = 2;
819
		break;
820
	case PLANE_Z:
821
	case PLANE_ANYZ:
822
		s_axis = 0;
823
		t_axis = 1;
824
		break;
825
	}
826
 
827
	r_nearzi = 0;
828
 
829
	for (i=0 ; i
830
	{
831
	// transform and project
832
		VectorSubtract (verts[vertpage][i].position, modelorg, local);
833
		TransformVector (local, transformed);
834
 
835
		if (transformed[2] < NEAR_CLIP)
836
			transformed[2] = NEAR_CLIP;
837
 
838
		lzi = 1.0 / transformed[2];
839
 
840
		if (lzi > r_nearzi)	// for mipmap finding
841
			r_nearzi = lzi;
842
 
843
	// FIXME: build x/yscale into transform?
844
		scale = xscale * lzi;
845
		u = (xcenter + scale*transformed[0]);
846
		if (u < r_refdef.fvrectx_adj)
847
			u = r_refdef.fvrectx_adj;
848
		if (u > r_refdef.fvrectright_adj)
849
			u = r_refdef.fvrectright_adj;
850
 
851
		scale = yscale * lzi;
852
		v = (ycenter - scale*transformed[1]);
853
		if (v < r_refdef.fvrecty_adj)
854
			v = r_refdef.fvrecty_adj;
855
		if (v > r_refdef.fvrectbottom_adj)
856
			v = r_refdef.fvrectbottom_adj;
857
 
858
		pverts[i].u = u;
859
		pverts[i].v = v;
860
		pverts[i].zi = lzi;
861
		pverts[i].s = verts[vertpage][i].position[s_axis];
862
		pverts[i].t = verts[vertpage][i].position[t_axis];
863
	}
864
 
865
// build the polygon descriptor, including fa, r_nearzi, and u, v, s, t, and z
866
// for each vertex
867
	r_polydesc.numverts = lnumverts;
868
	r_polydesc.nearzi = r_nearzi;
869
	r_polydesc.pcurrentface = fa;
870
	r_polydesc.pverts = pverts;
871
 
872
// draw the polygon
873
	D_DrawPoly ();
874
}
875
 
876
 
877
/*
878
================
879
R_ZDrawSubmodelPolys
880
================
881
*/
882
void R_ZDrawSubmodelPolys (model_t *pmodel)
883
{
884
	int			i, numsurfaces;
885
	msurface_t	*psurf;
886
	float		dot;
887
	mplane_t	*pplane;
888
 
889
	psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
890
	numsurfaces = pmodel->nummodelsurfaces;
891
 
892
	for (i=0 ; i
893
	{
894
	// find which side of the node we are on
895
		pplane = psurf->plane;
896
 
897
		dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
898
 
899
	// draw the polygon
900
		if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
901
			(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
902
		{
903
		// FIXME: use bounding-box-based frustum clipping info?
904
			R_RenderPoly (psurf, 15);
905
		}
906
	}
907
}
908