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
// r_main.c
21
 
22
#include "quakedef.h"
23
#include "r_local.h"
24
 
25
//define	PASSAGES
26
 
27
void		*colormap;
28
vec3_t		viewlightvec;
29
alight_t	r_viewlighting = {128, 192, viewlightvec};
30
float		r_time1;
31
int			r_numallocatededges;
32
qboolean	r_drawpolys;
33
qboolean	r_drawculledpolys;
34
qboolean	r_worldpolysbacktofront;
35
qboolean	r_recursiveaffinetriangles = true;
36
int			r_pixbytes = 1;
37
float		r_aliasuvscale = 1.0;
38
int			r_outofsurfaces;
39
int			r_outofedges;
40
 
41
qboolean	r_dowarp, r_dowarpold, r_viewchanged;
42
 
43
int			numbtofpolys;
44
btofpoly_t	*pbtofpolys;
45
mvertex_t	*r_pcurrentvertbase;
46
 
47
int			c_surf;
48
int			r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
49
qboolean	r_surfsonstack;
50
int			r_clipflags;
51
 
52
byte		*r_warpbuffer;
53
 
54
byte		*r_stack_start;
55
 
56
qboolean	r_fov_greater_than_90;
57
 
58
//
59
// view origin
60
//
61
vec3_t	vup, base_vup;
62
vec3_t	vpn, base_vpn;
63
vec3_t	vright, base_vright;
64
vec3_t	r_origin;
65
 
66
//
67
// screen size info
68
//
69
refdef_t	r_refdef;
70
float		xcenter, ycenter;
71
float		xscale, yscale;
72
float		xscaleinv, yscaleinv;
73
float		xscaleshrink, yscaleshrink;
74
float		aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
75
 
76
int		screenwidth;
77
 
78
float	pixelAspect;
79
float	screenAspect;
80
float	verticalFieldOfView;
81
float	xOrigin, yOrigin;
82
 
83
mplane_t	screenedge[4];
84
 
85
//
86
// refresh flags
87
//
88
int		r_framecount = 1;	// so frame counts initialized to 0 don't match
89
int		r_visframecount;
90
int		d_spanpixcount;
91
int		r_polycount;
92
int		r_drawnpolycount;
93
int		r_wholepolycount;
94
 
95
#define		VIEWMODNAME_LENGTH	256
96
char		viewmodname[VIEWMODNAME_LENGTH+1];
97
int			modcount;
98
 
99
int			*pfrustum_indexes[4];
100
int			r_frustum_indexes[4*6];
101
 
102
int		reinit_surfcache = 1;	// if 1, surface cache is currently empty and
103
								// must be reinitialized for current cache size
104
 
105
mleaf_t		*r_viewleaf, *r_oldviewleaf;
106
 
107
texture_t	*r_notexture_mip;
108
 
109
float		r_aliastransition, r_resfudge;
110
 
111
int		d_lightstylevalue[256];	// 8.8 fraction of base light value
112
 
113
float	dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
114
float	se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;
115
 
116
void R_MarkLeaves (void);
117
 
118
cvar_t	r_draworder = {"r_draworder","0"};
119
cvar_t	r_speeds = {"r_speeds","0"};
120
cvar_t	r_timegraph = {"r_timegraph","0"};
121
cvar_t	r_graphheight = {"r_graphheight","10"};
122
cvar_t	r_clearcolor = {"r_clearcolor","2"};
123
cvar_t	r_waterwarp = {"r_waterwarp","1"};
124
cvar_t	r_fullbright = {"r_fullbright","0"};
125
cvar_t	r_drawentities = {"r_drawentities","1"};
126
cvar_t	r_drawviewmodel = {"r_drawviewmodel","1"};
127
cvar_t	r_aliasstats = {"r_polymodelstats","0"};
128
cvar_t	r_dspeeds = {"r_dspeeds","0"};
129
cvar_t	r_drawflat = {"r_drawflat", "0"};
130
cvar_t	r_ambient = {"r_ambient", "0"};
131
cvar_t	r_reportsurfout = {"r_reportsurfout", "0"};
132
cvar_t	r_maxsurfs = {"r_maxsurfs", "0"};
133
cvar_t	r_numsurfs = {"r_numsurfs", "0"};
134
cvar_t	r_reportedgeout = {"r_reportedgeout", "0"};
135
cvar_t	r_maxedges = {"r_maxedges", "0"};
136
cvar_t	r_numedges = {"r_numedges", "0"};
137
cvar_t	r_aliastransbase = {"r_aliastransbase", "200"};
138
cvar_t	r_aliastransadj = {"r_aliastransadj", "100"};
139
 
140
extern cvar_t	scr_fov;
141
 
142
void CreatePassages (void);
143
void SetVisibilityByPassages (void);
144
 
145
/*
146
==================
147
R_InitTextures
148
==================
149
*/
150
void	R_InitTextures (void)
151
{
152
	int		x,y, m;
153
	byte	*dest;
154
 
155
// create a simple checkerboard texture for the default
156
	r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture");
157
 
158
	r_notexture_mip->width = r_notexture_mip->height = 16;
159
	r_notexture_mip->offsets[0] = sizeof(texture_t);
160
	r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16;
161
	r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8;
162
	r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4;
163
 
164
	for (m=0 ; m<4 ; m++)
165
	{
166
		dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];
167
		for (y=0 ; y< (16>>m) ; y++)
168
			for (x=0 ; x< (16>>m) ; x++)
169
			{
170
				if (  (y< (8>>m) ) ^ (x< (8>>m) ) )
171
					*dest++ = 0;
172
				else
173
					*dest++ = 0xff;
174
			}
175
	}
176
}
177
 
178
/*
179
===============
180
R_Init
181
===============
182
*/
183
void R_Init (void)
184
{
185
	int		dummy;
186
 
187
// get stack position so we can guess if we are going to overflow
188
	r_stack_start = (byte *)&dummy;
189
 
190
	R_InitTurb ();
191
 
192
	Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
193
	Cmd_AddCommand ("pointfile", R_ReadPointFile_f);
194
 
195
	Cvar_RegisterVariable (&r_draworder);
196
	Cvar_RegisterVariable (&r_speeds);
197
	Cvar_RegisterVariable (&r_timegraph);
198
	Cvar_RegisterVariable (&r_graphheight);
199
	Cvar_RegisterVariable (&r_drawflat);
200
	Cvar_RegisterVariable (&r_ambient);
201
	Cvar_RegisterVariable (&r_clearcolor);
202
	Cvar_RegisterVariable (&r_waterwarp);
203
	Cvar_RegisterVariable (&r_fullbright);
204
	Cvar_RegisterVariable (&r_drawentities);
205
	Cvar_RegisterVariable (&r_drawviewmodel);
206
	Cvar_RegisterVariable (&r_aliasstats);
207
	Cvar_RegisterVariable (&r_dspeeds);
208
	Cvar_RegisterVariable (&r_reportsurfout);
209
	Cvar_RegisterVariable (&r_maxsurfs);
210
	Cvar_RegisterVariable (&r_numsurfs);
211
	Cvar_RegisterVariable (&r_reportedgeout);
212
	Cvar_RegisterVariable (&r_maxedges);
213
	Cvar_RegisterVariable (&r_numedges);
214
	Cvar_RegisterVariable (&r_aliastransbase);
215
	Cvar_RegisterVariable (&r_aliastransadj);
216
 
217
	Cvar_SetValue ("r_maxedges", (float)NUMSTACKEDGES);
218
	Cvar_SetValue ("r_maxsurfs", (float)NUMSTACKSURFACES);
219
 
220
	view_clipplanes[0].leftedge = true;
221
	view_clipplanes[1].rightedge = true;
222
	view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
223
			view_clipplanes[3].leftedge = false;
224
	view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
225
			view_clipplanes[3].rightedge = false;
226
 
227
	r_refdef.xOrigin = XCENTERING;
228
	r_refdef.yOrigin = YCENTERING;
229
 
230
	R_InitParticles ();
231
 
232
// TODO: collect 386-specific code in one place
233
#if	id386
234
	Sys_MakeCodeWriteable ((long)R_EdgeCodeStart,
235
					     (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart);
236
#endif	// id386
237
 
238
	D_Init ();
239
}
240
 
241
/*
242
===============
243
R_NewMap
244
===============
245
*/
246
void R_NewMap (void)
247
{
248
	int		i;
249
 
250
// clear out efrags in case the level hasn't been reloaded
251
// FIXME: is this one short?
252
	for (i=0 ; inumleafs ; i++)
253
		cl.worldmodel->leafs[i].efrags = NULL;
254
 
255
	r_viewleaf = NULL;
256
	R_ClearParticles ();
257
 
258
	r_cnumsurfs = r_maxsurfs.value;
259
 
260
	if (r_cnumsurfs <= MINSURFACES)
261
		r_cnumsurfs = MINSURFACES;
262
 
263
	if (r_cnumsurfs > NUMSTACKSURFACES)
264
	{
265
		surfaces = Hunk_AllocName (r_cnumsurfs * sizeof(surf_t), "surfaces");
266
		surface_p = surfaces;
267
		surf_max = &surfaces[r_cnumsurfs];
268
		r_surfsonstack = false;
269
	// surface 0 doesn't really exist; it's just a dummy because index 0
270
	// is used to indicate no edge attached to surface
271
		surfaces--;
272
		R_SurfacePatch ();
273
	}
274
	else
275
	{
276
		r_surfsonstack = true;
277
	}
278
 
279
	r_maxedgesseen = 0;
280
	r_maxsurfsseen = 0;
281
 
282
	r_numallocatededges = r_maxedges.value;
283
 
284
	if (r_numallocatededges < MINEDGES)
285
		r_numallocatededges = MINEDGES;
286
 
287
	if (r_numallocatededges <= NUMSTACKEDGES)
288
	{
289
		auxedges = NULL;
290
	}
291
	else
292
	{
293
		auxedges = Hunk_AllocName (r_numallocatededges * sizeof(edge_t),
294
								   "edges");
295
	}
296
 
297
	r_dowarpold = false;
298
	r_viewchanged = false;
299
#ifdef PASSAGES
300
CreatePassages ();
301
#endif
302
}
303
 
304
 
305
/*
306
===============
307
R_SetVrect
308
===============
309
*/
310
void R_SetVrect (vrect_t *pvrectin, vrect_t *pvrect, int lineadj)
311
{
312
	int		h;
313
	float	size;
314
 
315
	size = scr_viewsize.value > 100 ? 100 : scr_viewsize.value;
316
	if (cl.intermission)
317
	{
318
		size = 100;
319
		lineadj = 0;
320
	}
321
	size /= 100;
322
 
323
	h = pvrectin->height - lineadj;
324
	pvrect->width = pvrectin->width * size;
325
	if (pvrect->width < 96)
326
	{
327
		size = 96.0 / pvrectin->width;
328
		pvrect->width = 96;	// min for icons
329
	}
330
	pvrect->width &= ~7;
331
	pvrect->height = pvrectin->height * size;
332
	if (pvrect->height > pvrectin->height - lineadj)
333
		pvrect->height = pvrectin->height - lineadj;
334
 
335
	pvrect->height &= ~1;
336
 
337
	pvrect->x = (pvrectin->width - pvrect->width)/2;
338
	pvrect->y = (h - pvrect->height)/2;
339
 
340
	{
341
		if (lcd_x.value)
342
		{
343
			pvrect->y >>= 1;
344
			pvrect->height >>= 1;
345
		}
346
	}
347
}
348
 
349
 
350
/*
351
===============
352
R_ViewChanged
353
 
354
Called every time the vid structure or r_refdef changes.
355
Guaranteed to be called before the first refresh
356
===============
357
*/
358
void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect)
359
{
360
	int		i;
361
	float	res_scale;
362
 
363
	r_viewchanged = true;
364
 
365
	R_SetVrect (pvrect, &r_refdef.vrect, lineadj);
366
 
367
	r_refdef.horizontalFieldOfView = 2.0 * tan (r_refdef.fov_x/360*M_PI);
368
	r_refdef.fvrectx = (float)r_refdef.vrect.x;
369
	r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5;
370
	r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1;
371
	r_refdef.fvrecty = (float)r_refdef.vrect.y;
372
	r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5;
373
	r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
374
	r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1;
375
	r_refdef.fvrectright = (float)r_refdef.vrectright;
376
	r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5;
377
	r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99;
378
	r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
379
	r_refdef.fvrectbottom = (float)r_refdef.vrectbottom;
380
	r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5;
381
 
382
	r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale);
383
	r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale);
384
	r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale);
385
	r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale);
386
	r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
387
			r_refdef.aliasvrect.width;
388
	r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
389
			r_refdef.aliasvrect.height;
390
 
391
	pixelAspect = aspect;
392
	xOrigin = r_refdef.xOrigin;
393
	yOrigin = r_refdef.yOrigin;
394
 
395
	screenAspect = r_refdef.vrect.width*pixelAspect /
396
			r_refdef.vrect.height;
397
// 320*200 1.0 pixelAspect = 1.6 screenAspect
398
// 320*240 1.0 pixelAspect = 1.3333 screenAspect
399
// proper 320*200 pixelAspect = 0.8333333
400
 
401
	verticalFieldOfView = r_refdef.horizontalFieldOfView / screenAspect;
402
 
403
// values for perspective projection
404
// if math were exact, the values would range from 0.5 to to range+0.5
405
// hopefully they wll be in the 0.000001 to range+.999999 and truncate
406
// the polygon rasterization will never render in the first row or column
407
// but will definately render in the [range] row and column, so adjust the
408
// buffer origin to get an exact edge to edge fill
409
	xcenter = ((float)r_refdef.vrect.width * XCENTERING) +
410
			r_refdef.vrect.x - 0.5;
411
	aliasxcenter = xcenter * r_aliasuvscale;
412
	ycenter = ((float)r_refdef.vrect.height * YCENTERING) +
413
			r_refdef.vrect.y - 0.5;
414
	aliasycenter = ycenter * r_aliasuvscale;
415
 
416
	xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
417
	aliasxscale = xscale * r_aliasuvscale;
418
	xscaleinv = 1.0 / xscale;
419
	yscale = xscale * pixelAspect;
420
	aliasyscale = yscale * r_aliasuvscale;
421
	yscaleinv = 1.0 / yscale;
422
	xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView;
423
	yscaleshrink = xscaleshrink*pixelAspect;
424
 
425
// left side clip
426
	screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView);
427
	screenedge[0].normal[1] = 0;
428
	screenedge[0].normal[2] = 1;
429
	screenedge[0].type = PLANE_ANYZ;
430
 
431
// right side clip
432
	screenedge[1].normal[0] =
433
			1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView);
434
	screenedge[1].normal[1] = 0;
435
	screenedge[1].normal[2] = 1;
436
	screenedge[1].type = PLANE_ANYZ;
437
 
438
// top side clip
439
	screenedge[2].normal[0] = 0;
440
	screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
441
	screenedge[2].normal[2] = 1;
442
	screenedge[2].type = PLANE_ANYZ;
443
 
444
// bottom side clip
445
	screenedge[3].normal[0] = 0;
446
	screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
447
	screenedge[3].normal[2] = 1;
448
	screenedge[3].type = PLANE_ANYZ;
449
 
450
	for (i=0 ; i<4 ; i++)
451
		VectorNormalize (screenedge[i].normal);
452
 
453
	res_scale = sqrt ((double)(r_refdef.vrect.width * r_refdef.vrect.height) /
454
			          (320.0 * 152.0)) *
455
			(2.0 / r_refdef.horizontalFieldOfView);
456
	r_aliastransition = r_aliastransbase.value * res_scale;
457
	r_resfudge = r_aliastransadj.value * res_scale;
458
 
459
	if (scr_fov.value <= 90.0)
460
		r_fov_greater_than_90 = false;
461
	else
462
		r_fov_greater_than_90 = true;
463
 
464
// TODO: collect 386-specific code in one place
465
#if	id386
466
	if (r_pixbytes == 1)
467
	{
468
		Sys_MakeCodeWriteable ((long)R_Surf8Start,
469
						     (long)R_Surf8End - (long)R_Surf8Start);
470
		colormap = vid.colormap;
471
		R_Surf8Patch ();
472
	}
473
	else
474
	{
475
		Sys_MakeCodeWriteable ((long)R_Surf16Start,
476
						     (long)R_Surf16End - (long)R_Surf16Start);
477
		colormap = vid.colormap16;
478
		R_Surf16Patch ();
479
	}
480
#endif	// id386
481
 
482
	D_ViewChanged ();
483
}
484
 
485
 
486
/*
487
===============
488
R_MarkLeaves
489
===============
490
*/
491
void R_MarkLeaves (void)
492
{
493
	byte	*vis;
494
	mnode_t	*node;
495
	int		i;
496
 
497
	if (r_oldviewleaf == r_viewleaf)
498
		return;
499
 
500
	r_visframecount++;
501
	r_oldviewleaf = r_viewleaf;
502
 
503
	vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
504
 
505
	for (i=0 ; inumleafs ; i++)
506
	{
507
		if (vis[i>>3] & (1<<(i&7)))
508
		{
509
			node = (mnode_t *)&cl.worldmodel->leafs[i+1];
510
			do
511
			{
512
				if (node->visframe == r_visframecount)
513
					break;
514
				node->visframe = r_visframecount;
515
				node = node->parent;
516
			} while (node);
517
		}
518
	}
519
}
520
 
521
 
522
/*
523
=============
524
R_DrawEntitiesOnList
525
=============
526
*/
527
void R_DrawEntitiesOnList (void)
528
{
529
	int			i, j;
530
	int			lnum;
531
	alight_t	lighting;
532
// FIXME: remove and do real lighting
533
	float		lightvec[3] = {-1, 0, 0};
534
	vec3_t		dist;
535
	float		add;
536
 
537
	if (!r_drawentities.value)
538
		return;
539
 
540
	for (i=0 ; i
541
	{
542
		currententity = cl_visedicts[i];
543
 
544
		if (currententity == &cl_entities[cl.viewentity])
545
			continue;	// don't draw the player
546
 
547
		switch (currententity->model->type)
548
		{
549
		case mod_sprite:
550
			VectorCopy (currententity->origin, r_entorigin);
551
			VectorSubtract (r_origin, r_entorigin, modelorg);
552
			R_DrawSprite ();
553
			break;
554
 
555
		case mod_alias:
556
			VectorCopy (currententity->origin, r_entorigin);
557
			VectorSubtract (r_origin, r_entorigin, modelorg);
558
 
559
		// see if the bounding box lets us trivially reject, also sets
560
		// trivial accept status
561
			if (R_AliasCheckBBox ())
562
			{
563
				j = R_LightPoint (currententity->origin);
564
 
565
				lighting.ambientlight = j;
566
				lighting.shadelight = j;
567
 
568
				lighting.plightvec = lightvec;
569
 
570
				for (lnum=0 ; lnum
571
				{
572
					if (cl_dlights[lnum].die >= cl.time)
573
					{
574
						VectorSubtract (currententity->origin,
575
										cl_dlights[lnum].origin,
576
										dist);
577
						add = cl_dlights[lnum].radius - Length(dist);
578
 
579
						if (add > 0)
580
							lighting.ambientlight += add;
581
					}
582
				}
583
 
584
			// clamp lighting so it doesn't overbright as much
585
				if (lighting.ambientlight > 128)
586
					lighting.ambientlight = 128;
587
				if (lighting.ambientlight + lighting.shadelight > 192)
588
					lighting.shadelight = 192 - lighting.ambientlight;
589
 
590
				R_AliasDrawModel (&lighting);
591
			}
592
 
593
			break;
594
 
595
		default:
596
			break;
597
		}
598
	}
599
}
600
 
601
/*
602
=============
603
R_DrawViewModel
604
=============
605
*/
606
void R_DrawViewModel (void)
607
{
608
// FIXME: remove and do real lighting
609
	float		lightvec[3] = {-1, 0, 0};
610
	int			j;
611
	int			lnum;
612
	vec3_t		dist;
613
	float		add;
614
	dlight_t	*dl;
615
 
616
	if (!r_drawviewmodel.value || r_fov_greater_than_90)
617
		return;
618
 
619
	if (cl.items & IT_INVISIBILITY)
620
		return;
621
 
622
	if (cl.stats[STAT_HEALTH] <= 0)
623
		return;
624
 
625
	currententity = &cl.viewent;
626
	if (!currententity->model)
627
		return;
628
 
629
	VectorCopy (currententity->origin, r_entorigin);
630
	VectorSubtract (r_origin, r_entorigin, modelorg);
631
 
632
	VectorCopy (vup, viewlightvec);
633
	VectorInverse (viewlightvec);
634
 
635
	j = R_LightPoint (currententity->origin);
636
 
637
	if (j < 24)
638
		j = 24;		// allways give some light on gun
639
	r_viewlighting.ambientlight = j;
640
	r_viewlighting.shadelight = j;
641
 
642
// add dynamic lights
643
	for (lnum=0 ; lnum
644
	{
645
		dl = &cl_dlights[lnum];
646
		if (!dl->radius)
647
			continue;
648
		if (!dl->radius)
649
			continue;
650
		if (dl->die < cl.time)
651
			continue;
652
 
653
		VectorSubtract (currententity->origin, dl->origin, dist);
654
		add = dl->radius - Length(dist);
655
		if (add > 0)
656
			r_viewlighting.ambientlight += add;
657
	}
658
 
659
// clamp lighting so it doesn't overbright as much
660
	if (r_viewlighting.ambientlight > 128)
661
		r_viewlighting.ambientlight = 128;
662
	if (r_viewlighting.ambientlight + r_viewlighting.shadelight > 192)
663
		r_viewlighting.shadelight = 192 - r_viewlighting.ambientlight;
664
 
665
	r_viewlighting.plightvec = lightvec;
666
 
667
#ifdef QUAKE2
668
	cl.light_level = r_viewlighting.ambientlight;
669
#endif
670
 
671
	R_AliasDrawModel (&r_viewlighting);
672
}
673
 
674
 
675
/*
676
=============
677
R_BmodelCheckBBox
678
=============
679
*/
680
int R_BmodelCheckBBox (model_t *clmodel, float *minmaxs)
681
{
682
	int			i, *pindex, clipflags;
683
	vec3_t		acceptpt, rejectpt;
684
	double		d;
685
 
686
	clipflags = 0;
687
 
688
	if (currententity->angles[0] || currententity->angles[1]
689
		|| currententity->angles[2])
690
	{
691
		for (i=0 ; i<4 ; i++)
692
		{
693
			d = DotProduct (currententity->origin, view_clipplanes[i].normal);
694
			d -= view_clipplanes[i].dist;
695
 
696
			if (d <= -clmodel->radius)
697
				return BMODEL_FULLY_CLIPPED;
698
 
699
			if (d <= clmodel->radius)
700
				clipflags |= (1<
701
		}
702
	}
703
	else
704
	{
705
		for (i=0 ; i<4 ; i++)
706
		{
707
		// generate accept and reject points
708
		// FIXME: do with fast look-ups or integer tests based on the sign bit
709
		// of the floating point values
710
 
711
			pindex = pfrustum_indexes[i];
712
 
713
			rejectpt[0] = minmaxs[pindex[0]];
714
			rejectpt[1] = minmaxs[pindex[1]];
715
			rejectpt[2] = minmaxs[pindex[2]];
716
 
717
			d = DotProduct (rejectpt, view_clipplanes[i].normal);
718
			d -= view_clipplanes[i].dist;
719
 
720
			if (d <= 0)
721
				return BMODEL_FULLY_CLIPPED;
722
 
723
			acceptpt[0] = minmaxs[pindex[3+0]];
724
			acceptpt[1] = minmaxs[pindex[3+1]];
725
			acceptpt[2] = minmaxs[pindex[3+2]];
726
 
727
			d = DotProduct (acceptpt, view_clipplanes[i].normal);
728
			d -= view_clipplanes[i].dist;
729
 
730
			if (d <= 0)
731
				clipflags |= (1<
732
		}
733
	}
734
 
735
	return clipflags;
736
}
737
 
738
 
739
/*
740
=============
741
R_DrawBEntitiesOnList
742
=============
743
*/
744
void R_DrawBEntitiesOnList (void)
745
{
746
	int			i, j, k, clipflags;
747
	vec3_t		oldorigin;
748
	model_t		*clmodel;
749
	float		minmaxs[6];
750
 
751
	if (!r_drawentities.value)
752
		return;
753
 
754
	VectorCopy (modelorg, oldorigin);
755
	insubmodel = true;
756
	r_dlightframecount = r_framecount;
757
 
758
	for (i=0 ; i
759
	{
760
		currententity = cl_visedicts[i];
761
 
762
		switch (currententity->model->type)
763
		{
764
		case mod_brush:
765
 
766
			clmodel = currententity->model;
767
 
768
		// see if the bounding box lets us trivially reject, also sets
769
		// trivial accept status
770
			for (j=0 ; j<3 ; j++)
771
			{
772
				minmaxs[j] = currententity->origin[j] +
773
						clmodel->mins[j];
774
				minmaxs[3+j] = currententity->origin[j] +
775
						clmodel->maxs[j];
776
			}
777
 
778
			clipflags = R_BmodelCheckBBox (clmodel, minmaxs);
779
 
780
			if (clipflags != BMODEL_FULLY_CLIPPED)
781
			{
782
				VectorCopy (currententity->origin, r_entorigin);
783
				VectorSubtract (r_origin, r_entorigin, modelorg);
784
			// FIXME: is this needed?
785
				VectorCopy (modelorg, r_worldmodelorg);
786
 
787
				r_pcurrentvertbase = clmodel->vertexes;
788
 
789
			// FIXME: stop transforming twice
790
				R_RotateBmodel ();
791
 
792
			// calculate dynamic lighting for bmodel if it's not an
793
			// instanced model
794
				if (clmodel->firstmodelsurface != 0)
795
				{
796
					for (k=0 ; k
797
					{
798
						if ((cl_dlights[k].die < cl.time) ||
799
							(!cl_dlights[k].radius))
800
						{
801
							continue;
802
						}
803
 
804
						R_MarkLights (&cl_dlights[k], 1<
805
							clmodel->nodes + clmodel->hulls[0].firstclipnode);
806
					}
807
				}
808
 
809
			// if the driver wants polygons, deliver those. Z-buffering is on
810
			// at this point, so no clipping to the world tree is needed, just
811
			// frustum clipping
812
				if (r_drawpolys | r_drawculledpolys)
813
				{
814
					R_ZDrawSubmodelPolys (clmodel);
815
				}
816
				else
817
				{
818
					r_pefragtopnode = NULL;
819
 
820
					for (j=0 ; j<3 ; j++)
821
					{
822
						r_emins[j] = minmaxs[j];
823
						r_emaxs[j] = minmaxs[3+j];
824
					}
825
 
826
					R_SplitEntityOnNode2 (cl.worldmodel->nodes);
827
 
828
					if (r_pefragtopnode)
829
					{
830
						currententity->topnode = r_pefragtopnode;
831
 
832
						if (r_pefragtopnode->contents >= 0)
833
						{
834
						// not a leaf; has to be clipped to the world BSP
835
							r_clipflags = clipflags;
836
							R_DrawSolidClippedSubmodelPolygons (clmodel);
837
						}
838
						else
839
						{
840
						// falls entirely in one leaf, so we just put all the
841
						// edges in the edge list and let 1/z sorting handle
842
						// drawing order
843
							R_DrawSubmodelPolygons (clmodel, clipflags);
844
						}
845
 
846
						currententity->topnode = NULL;
847
					}
848
				}
849
 
850
			// put back world rotation and frustum clipping
851
			// FIXME: R_RotateBmodel should just work off base_vxx
852
				VectorCopy (base_vpn, vpn);
853
				VectorCopy (base_vup, vup);
854
				VectorCopy (base_vright, vright);
855
				VectorCopy (base_modelorg, modelorg);
856
				VectorCopy (oldorigin, modelorg);
857
				R_TransformFrustum ();
858
			}
859
 
860
			break;
861
 
862
		default:
863
			break;
864
		}
865
	}
866
 
867
	insubmodel = false;
868
}
869
 
870
 
871
/*
872
================
873
R_EdgeDrawing
874
================
875
*/
876
void R_EdgeDrawing (void)
877
{
878
	edge_t	ledges[NUMSTACKEDGES +
879
				((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
880
	surf_t	lsurfs[NUMSTACKSURFACES +
881
				((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
882
 
883
	if (auxedges)
884
	{
885
		r_edges = auxedges;
886
	}
887
	else
888
	{
889
		r_edges =  (edge_t *)
890
				(((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
891
	}
892
 
893
	if (r_surfsonstack)
894
	{
895
		surfaces =  (surf_t *)
896
				(((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
897
		surf_max = &surfaces[r_cnumsurfs];
898
	// surface 0 doesn't really exist; it's just a dummy because index 0
899
	// is used to indicate no edge attached to surface
900
		surfaces--;
901
		R_SurfacePatch ();
902
	}
903
 
904
	R_BeginEdgeFrame ();
905
 
906
	if (r_dspeeds.value)
907
	{
908
		rw_time1 = Sys_FloatTime ();
909
	}
910
 
911
	R_RenderWorld ();
912
 
913
	if (r_drawculledpolys)
914
		R_ScanEdges ();
915
 
916
// only the world can be drawn back to front with no z reads or compares, just
917
// z writes, so have the driver turn z compares on now
918
	D_TurnZOn ();
919
 
920
	if (r_dspeeds.value)
921
	{
922
		rw_time2 = Sys_FloatTime ();
923
		db_time1 = rw_time2;
924
	}
925
 
926
	R_DrawBEntitiesOnList ();
927
 
928
	if (r_dspeeds.value)
929
	{
930
		db_time2 = Sys_FloatTime ();
931
		se_time1 = db_time2;
932
	}
933
 
934
	if (!r_dspeeds.value)
935
	{
936
		VID_UnlockBuffer ();
937
		S_ExtraUpdate ();	// don't let sound get messed up if going slow
938
		VID_LockBuffer ();
939
	}
940
 
941
	if (!(r_drawpolys | r_drawculledpolys))
942
		R_ScanEdges ();
943
}
944
 
945
 
946
/*
947
================
948
R_RenderView
949
 
950
r_refdef must be set before the first call
951
================
952
*/
953
void R_RenderView_ (void)
954
{
955
	byte	warpbuffer[WARP_WIDTH * WARP_HEIGHT];
956
 
957
	r_warpbuffer = warpbuffer;
958
 
959
	if (r_timegraph.value || r_speeds.value || r_dspeeds.value)
960
		r_time1 = Sys_FloatTime ();
961
 
962
	R_SetupFrame ();
963
 
964
#ifdef PASSAGES
965
SetVisibilityByPassages ();
966
#else
967
	R_MarkLeaves ();	// done here so we know if we're in water
968
#endif
969
 
970
// make FDIV fast. This reduces timing precision after we've been running for a
971
// while, so we don't do it globally.  This also sets chop mode, and we do it
972
// here so that setup stuff like the refresh area calculations match what's
973
// done in screen.c
974
	Sys_LowFPPrecision ();
975
 
976
	if (!cl_entities[0].model || !cl.worldmodel)
977
		Sys_Error ("R_RenderView: NULL worldmodel");
978
 
979
	if (!r_dspeeds.value)
980
	{
981
		VID_UnlockBuffer ();
982
		S_ExtraUpdate ();	// don't let sound get messed up if going slow
983
		VID_LockBuffer ();
984
	}
985
 
986
	R_EdgeDrawing ();
987
 
988
	if (!r_dspeeds.value)
989
	{
990
		VID_UnlockBuffer ();
991
		S_ExtraUpdate ();	// don't let sound get messed up if going slow
992
		VID_LockBuffer ();
993
	}
994
 
995
	if (r_dspeeds.value)
996
	{
997
		se_time2 = Sys_FloatTime ();
998
		de_time1 = se_time2;
999
	}
1000
 
1001
	R_DrawEntitiesOnList ();
1002
 
1003
	if (r_dspeeds.value)
1004
	{
1005
		de_time2 = Sys_FloatTime ();
1006
		dv_time1 = de_time2;
1007
	}
1008
 
1009
	R_DrawViewModel ();
1010
 
1011
	if (r_dspeeds.value)
1012
	{
1013
		dv_time2 = Sys_FloatTime ();
1014
		dp_time1 = Sys_FloatTime ();
1015
	}
1016
 
1017
	R_DrawParticles ();
1018
 
1019
	if (r_dspeeds.value)
1020
		dp_time2 = Sys_FloatTime ();
1021
 
1022
	if (r_dowarp)
1023
		D_WarpScreen ();
1024
 
1025
	V_SetContentsColor (r_viewleaf->contents);
1026
 
1027
	if (r_timegraph.value)
1028
		R_TimeGraph ();
1029
 
1030
	if (r_aliasstats.value)
1031
		R_PrintAliasStats ();
1032
 
1033
	if (r_speeds.value)
1034
		R_PrintTimes ();
1035
 
1036
	if (r_dspeeds.value)
1037
		R_PrintDSpeeds ();
1038
 
1039
	if (r_reportsurfout.value && r_outofsurfaces)
1040
		Con_Printf ("Short %d surfaces\n", r_outofsurfaces);
1041
 
1042
	if (r_reportedgeout.value && r_outofedges)
1043
		Con_Printf ("Short roughly %d edges\n", r_outofedges * 2 / 3);
1044
 
1045
// back to high floating-point precision
1046
	Sys_HighFPPrecision ();
1047
}
1048
 
1049
void R_RenderView (void)
1050
{
1051
	int		dummy;
1052
	int		delta;
1053
 
1054
	delta = (byte *)&dummy - r_stack_start;
1055
	if (delta < -10000 || delta > 10000)
1056
		Sys_Error ("R_RenderView: called without enough stack");
1057
 
1058
	if ( Hunk_LowMark() & 3 )
1059
		Sys_Error ("Hunk is missaligned");
1060
 
1061
	if ( (long)(&dummy) & 3 )
1062
		Sys_Error ("Stack is missaligned");
1063
 
1064
	if ( (long)(&r_warpbuffer) & 3 )
1065
		Sys_Error ("Globals are missaligned");
1066
 
1067
	R_RenderView_ ();
1068
}
1069
 
1070
/*
1071
================
1072
R_InitTurb
1073
================
1074
*/
1075
void R_InitTurb (void)
1076
{
1077
	int		i;
1078
 
1079
	for (i=0 ; i<(SIN_BUFFER_SIZE) ; i++)
1080
	{
1081
		sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
1082
		intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2;	// AMP2, not 20
1083
	}
1084
}
1085