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_main.c
21
22#include "quakedef.h"
23
24entity_t	r_worldentity;
25
26qboolean	r_cache_thrash;		// compatability
27
28vec3_t		modelorg, r_entorigin;
29entity_t	*currententity;
30
31int			r_visframecount;	// bumped when going to a new PVS
32int			r_framecount;		// used for dlight push checking
33
34mplane_t	frustum[4];
35
36int			c_brush_polys, c_alias_polys;
37
38qboolean	envmap;				// true during envmap command capture
39
40int			currenttexture = -1;		// to avoid unnecessary texture sets
41
42int			cnttextures[2] = {-1, -1};     // cached
43
44int			particletexture;	// little dot for particles
45int			playertextures;		// up to 16 color translated skins
46
47int			mirrortexturenum;	// quake texturenum, not gltexturenum
48qboolean	mirror;
49mplane_t	*mirror_plane;
50
51//
52// view origin
53//
54vec3_t	vup;
55vec3_t	vpn;
56vec3_t	vright;
57vec3_t	r_origin;
58
59float	r_world_matrix[16];
60float	r_base_world_matrix[16];
61
62//
63// screen size info
64//
65refdef_t	r_refdef;
66
67mleaf_t		*r_viewleaf, *r_oldviewleaf;
68
69texture_t	*r_notexture_mip;
70
71int		d_lightstylevalue[256];	// 8.8 fraction of base light value
72
73
74void R_MarkLeaves (void);
75
76cvar_t	r_norefresh = CVAR2("r_norefresh","0");
77cvar_t	r_drawentities = CVAR2("r_drawentities","1");
78cvar_t	r_drawviewmodel = CVAR2("r_drawviewmodel","1");
79cvar_t	r_speeds = CVAR2("r_speeds","0");
80cvar_t	r_fullbright = CVAR2("r_fullbright","0");
81cvar_t	r_lightmap = CVAR2("r_lightmap","0");
82cvar_t	r_shadows = CVAR2("r_shadows","0");
83cvar_t	r_mirroralpha = CVAR2("r_mirroralpha","1");
84cvar_t	r_wateralpha = CVAR2("r_wateralpha","1");
85cvar_t	r_dynamic = CVAR2("r_dynamic","1");
86cvar_t	r_novis = CVAR2("r_novis","0");
87cvar_t	r_netgraph = CVAR2("r_netgraph","0");
88
89cvar_t	gl_clear = CVAR2("gl_clear","0");
90cvar_t	gl_cull = CVAR2("gl_cull","1");
91cvar_t	gl_texsort = CVAR2("gl_texsort","1");
92cvar_t	gl_smoothmodels = CVAR2("gl_smoothmodels","1");
93cvar_t	gl_affinemodels = CVAR2("gl_affinemodels","0");
94cvar_t	gl_polyblend = CVAR2("gl_polyblend","1");
95cvar_t	gl_flashblend = CVAR2("gl_flashblend","1");
96cvar_t	gl_playermip = CVAR2("gl_playermip","0");
97cvar_t	gl_nocolors = CVAR2("gl_nocolors","0");
98cvar_t	gl_keeptjunctions = CVAR2("gl_keeptjunctions","1");
99cvar_t	gl_reporttjunctions = CVAR2("gl_reporttjunctions","0");
100cvar_t	gl_finish = CVAR2("gl_finish","0");
101
102extern	cvar_t	gl_ztrick;
103extern	cvar_t	scr_fov;
104/*
105=================
106R_CullBox
107
108Returns true if the box is completely outside the frustom
109=================
110*/
111qboolean R_CullBox (vec3_t mins, vec3_t maxs)
112{
113	int		i;
114
115	for (i=0 ; i<4 ; i++)
116		if (BoxOnPlaneSide (mins, maxs, &frustum[i]) == 2)
117			return true;
118	return false;
119}
120
121
122void R_RotateForEntity (entity_t *e)
123{
124    glTranslatef (e->origin[0],  e->origin[1],  e->origin[2]);
125
126    glRotatef (e->angles[1],  0, 0, 1);
127    glRotatef (-e->angles[0],  0, 1, 0);
128	//ZOID: fixed z angle
129    glRotatef (e->angles[2],  1, 0, 0);
130}
131
132/*
133=============================================================
134
135  SPRITE MODELS
136
137=============================================================
138*/
139
140/*
141================
142R_GetSpriteFrame
143================
144*/
145mspriteframe_t *R_GetSpriteFrame (entity_t *currententity)
146{
147	msprite_t		*psprite;
148	mspritegroup_t	*pspritegroup;
149	mspriteframe_t	*pspriteframe;
150	int				i, numframes, frame;
151	float			*pintervals, fullinterval, targettime, time;
152
153	psprite = currententity->model->cache.data;
154	frame = currententity->frame;
155
156	if ((frame >= psprite->numframes) || (frame < 0))
157	{
158		Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
159		frame = 0;
160	}
161
162	if (psprite->frames[frame].type == SPR_SINGLE)
163	{
164		pspriteframe = psprite->frames[frame].frameptr;
165	}
166	else
167	{
168		pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
169		pintervals = pspritegroup->intervals;
170		numframes = pspritegroup->numframes;
171		fullinterval = pintervals[numframes-1];
172
173		time = cl.time + currententity->syncbase;
174
175	// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
176	// are positive, so we don't have to worry about division by 0
177		targettime = time - ((int)(time / fullinterval)) * fullinterval;
178
179		for (i=0 ; i<(numframes-1) ; i++)
180		{
181			if (pintervals[i] > targettime)
182				break;
183		}
184
185		pspriteframe = pspritegroup->frames[i];
186	}
187
188	return pspriteframe;
189}
190
191
192/*
193=================
194R_DrawSpriteModel
195
196=================
197*/
198void R_DrawSpriteModel (entity_t *e)
199{
200	vec3_t	point;
201	mspriteframe_t	*frame;
202	float		*up, *right;
203	vec3_t		v_forward, v_right, v_up;
204	msprite_t		*psprite;
205
206	// don't even bother culling, because it's just a single
207	// polygon without a surface cache
208	frame = R_GetSpriteFrame (e);
209	psprite = currententity->model->cache.data;
210
211	if (psprite->type == SPR_ORIENTED)
212	{	// bullet marks on walls
213		AngleVectors (currententity->angles, v_forward, v_right, v_up);
214		up = v_up;
215		right = v_right;
216	}
217	else
218	{	// normal sprite
219		up = vup;
220		right = vright;
221	}
222
223	glColor3f (1,1,1);
224
225	GL_DisableMultitexture();
226
227    GL_Bind(frame->gl_texturenum);
228
229	glEnable (GL_ALPHA_TEST);
230
231#ifdef USE_OPENGLES
232	// !!! Need to implement this !!!
233
234#else
235	glBegin (GL_QUADS);
236
237	glTexCoord2f (0, 1);
238	VectorMA (e->origin, frame->down, up, point);
239	VectorMA (point, frame->left, right, point);
240	glVertex3fv (point);
241
242	glTexCoord2f (0, 0);
243	VectorMA (e->origin, frame->up, up, point);
244	VectorMA (point, frame->left, right, point);
245	glVertex3fv (point);
246
247	glTexCoord2f (1, 0);
248	VectorMA (e->origin, frame->up, up, point);
249	VectorMA (point, frame->right, right, point);
250	glVertex3fv (point);
251
252	glTexCoord2f (1, 1);
253	VectorMA (e->origin, frame->down, up, point);
254	VectorMA (point, frame->right, right, point);
255	glVertex3fv (point);
256
257	glEnd ();
258#endif
259
260	glDisable (GL_ALPHA_TEST);
261}
262
263/*
264=============================================================
265
266  ALIAS MODELS
267
268=============================================================
269*/
270
271
272#define NUMVERTEXNORMALS	162
273
274float	r_avertexnormals[NUMVERTEXNORMALS][3] = {
275#include "anorms.h"
276};
277
278vec3_t	shadevector;
279float	shadelight, ambientlight;
280
281// precalculated dot products for quantized angles
282#define SHADEDOT_QUANT 16
283float	r_avertexnormal_dots[SHADEDOT_QUANT][256] =
284#include "anorm_dots.h"
285;
286
287float	*shadedots = r_avertexnormal_dots[0];
288
289int	lastposenum;
290
291/*
292=============
293GL_DrawAliasFrame
294=============
295*/
296void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum)
297{
298	float 	l;
299	trivertx_t	*verts;
300	int		*order;
301	int		count;
302
303lastposenum = posenum;
304
305	verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
306	verts += posenum * paliashdr->poseverts;
307	order = (int *)((byte *)paliashdr + paliashdr->commands);
308
309	while (1)
310	{
311		// get the vertex count and primitive type
312		count = *order++;
313		if (!count)
314			break;		// done
315
316#ifdef USE_OPENGLES
317		{
318			int primType;
319			float color[3*256];
320			float vertex[3*256];
321			int c;
322			float* pColor;
323			float* pVertex;
324
325			if (count < 0)
326			{
327				count = -count;
328				primType = GL_TRIANGLE_FAN;
329			}
330			else
331				primType = GL_TRIANGLE_STRIP;
332
333			// texture coordinates come from the draw list
334			glTexCoordPointer(2, GL_FLOAT, 0, order);
335
336			pColor = color;
337			pVertex = vertex;
338			for(c = 0; c < count; c++)
339			{
340				// normals and vertexes come from the frame list
341				l = shadedots[verts->lightnormalindex] * shadelight;
342				*pColor++ = l;
343				*pColor++ = l;
344				*pColor++ = l;
345				*pVertex++ = verts->v[0];
346				*pVertex++ = verts->v[1];
347				*pVertex++ = verts->v[2];
348				verts++;
349			}
350
351			glColorPointer(3, GL_FLOAT, 0, color);
352			glVertexPointer(3, GL_FLOAT, 0, vertex);
353
354			glDrawArrays(primType, 0, count);
355
356			order += 2 * count;
357		}
358
359#else
360		if (count < 0)
361		{
362			count = -count;
363			glBegin (GL_TRIANGLE_FAN);
364		}
365		else
366			glBegin (GL_TRIANGLE_STRIP);
367
368		do
369		{
370			// texture coordinates come from the draw list
371			glTexCoord2f (((float *)order)[0], ((float *)order)[1]);
372			order += 2;
373
374			// normals and vertexes come from the frame list
375			l = shadedots[verts->lightnormalindex] * shadelight;
376			glColor3f (l, l, l);
377			glVertex3f (verts->v[0], verts->v[1], verts->v[2]);
378			verts++;
379		} while (--count);
380
381		glEnd ();
382#endif
383	}
384}
385
386
387/*
388=============
389GL_DrawAliasShadow
390=============
391*/
392extern	vec3_t			lightspot;
393
394void GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum)
395{
396	trivertx_t	*verts;
397	int		*order;
398	vec3_t	point;
399	float	height, lheight;
400	int		count;
401
402	lheight = currententity->origin[2] - lightspot[2];
403
404	height = 0;
405	verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
406	verts += posenum * paliashdr->poseverts;
407	order = (int *)((byte *)paliashdr + paliashdr->commands);
408
409	height = -lheight + 1.0;
410
411	while (1)
412	{
413		// get the vertex count and primitive type
414		count = *order++;
415		if (!count)
416			break;		// done
417
418#ifdef USE_OPENGLES
419
420		// !!! Implement this (based on GL_DrawAlias)
421		break;
422#else
423
424		if (count < 0)
425		{
426			count = -count;
427			glBegin (GL_TRIANGLE_FAN);
428		}
429		else
430			glBegin (GL_TRIANGLE_STRIP);
431
432		do
433		{
434			// texture coordinates come from the draw list
435			// (skipped for shadows) glTexCoord2fv ((float *)order);
436			order += 2;
437
438			// normals and vertexes come from the frame list
439			point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];
440			point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];
441			point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];
442
443			point[0] -= shadevector[0]*(point[2]+lheight);
444			point[1] -= shadevector[1]*(point[2]+lheight);
445			point[2] = height;
446//			height -= 0.001;
447			glVertex3fv (point);
448
449			verts++;
450		} while (--count);
451
452		glEnd ();
453
454#endif
455
456	}
457}
458
459
460
461/*
462=================
463R_SetupAliasFrame
464
465=================
466*/
467void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr)
468{
469	int				pose, numposes;
470	float			interval;
471
472	if ((frame >= paliashdr->numframes) || (frame < 0))
473	{
474		Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
475		frame = 0;
476	}
477
478	pose = paliashdr->frames[frame].firstpose;
479	numposes = paliashdr->frames[frame].numposes;
480
481	if (numposes > 1)
482	{
483		interval = paliashdr->frames[frame].interval;
484		pose += (int)(cl.time / interval) % numposes;
485	}
486
487	GL_DrawAliasFrame (paliashdr, pose);
488}
489
490
491
492/*
493=================
494R_DrawAliasModel
495
496=================
497*/
498void R_DrawAliasModel (entity_t *e)
499{
500	int			i;
501	int			lnum;
502	vec3_t		dist;
503	float		add;
504	model_t		*clmodel;
505	vec3_t		mins, maxs;
506	aliashdr_t	*paliashdr;
507	float		an;
508	int			anim;
509
510	clmodel = currententity->model;
511
512	VectorAdd (currententity->origin, clmodel->mins, mins);
513	VectorAdd (currententity->origin, clmodel->maxs, maxs);
514
515	if (R_CullBox (mins, maxs))
516		return;
517
518
519	VectorCopy (currententity->origin, r_entorigin);
520	VectorSubtract (r_origin, r_entorigin, modelorg);
521
522	//
523	// get lighting information
524	//
525
526	ambientlight = shadelight = R_LightPoint (currententity->origin);
527
528	// allways give the gun some light
529	if (e == &cl.viewent && ambientlight < 24)
530		ambientlight = shadelight = 24;
531
532	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
533	{
534		if (cl_dlights[lnum].die >= cl.time)
535		{
536			VectorSubtract (currententity->origin,
537							cl_dlights[lnum].origin,
538							dist);
539			add = cl_dlights[lnum].radius - Length(dist);
540
541			if (add > 0) {
542				ambientlight += add;
543				//ZOID models should be affected by dlights as well
544				shadelight += add;
545			}
546		}
547	}
548
549	// clamp lighting so it doesn't overbright as much
550	if (ambientlight > 128)
551		ambientlight = 128;
552	if (ambientlight + shadelight > 192)
553		shadelight = 192 - ambientlight;
554
555	// ZOID: never allow players to go totally black
556	if (!strcmp(clmodel->name, "progs/player.mdl")) {
557		if (ambientlight < 8)
558			ambientlight = shadelight = 8;
559
560	} else if (!strcmp (clmodel->name, "progs/flame2.mdl")
561		|| !strcmp (clmodel->name, "progs/flame.mdl") )
562		// HACK HACK HACK -- no fullbright colors, so make torches full light
563		ambientlight = shadelight = 256;
564
565	shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
566	shadelight = shadelight / 200.0;
567
568	an = e->angles[1]/180*M_PI;
569	shadevector[0] = cos(-an);
570	shadevector[1] = sin(-an);
571	shadevector[2] = 1;
572	VectorNormalize (shadevector);
573
574	//
575	// locate the proper data
576	//
577	paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);
578
579	c_alias_polys += paliashdr->numtris;
580
581	//
582	// draw all the triangles
583	//
584
585	GL_DisableMultitexture();
586
587    glPushMatrix ();
588	R_RotateForEntity (e);
589
590	if (!strcmp (clmodel->name, "progs/eyes.mdl") ) {
591		glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8));
592	// double size of eyes, since they are really hard to see in gl
593		glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2);
594	} else {
595		glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
596		glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
597	}
598
599	anim = (int)(cl.time*10) & 3;
600    GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]);
601
602	// we can't dynamically colormap textures, so they are cached
603	// seperately for the players.  Heads are just uncolored.
604	if (currententity->scoreboard && !gl_nocolors.value)
605	{
606		i = currententity->scoreboard - cl.players;
607		if (!currententity->scoreboard->skin) {
608			Skin_Find(currententity->scoreboard);
609			R_TranslatePlayerSkin(i);
610		}
611		if (i >= 0 && i<MAX_CLIENTS)
612		    GL_Bind(playertextures + i);
613	}
614
615	if (gl_smoothmodels.value)
616		glShadeModel (GL_SMOOTH);
617	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
618
619	if (gl_affinemodels.value)
620		glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
621
622	R_SetupAliasFrame (currententity->frame, paliashdr);
623
624	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
625
626	glShadeModel (GL_FLAT);
627	if (gl_affinemodels.value)
628		glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
629
630	glPopMatrix ();
631
632	if (r_shadows.value)
633	{
634		glPushMatrix ();
635		R_RotateForEntity (e);
636		glDisable (GL_TEXTURE_2D);
637		glEnable (GL_BLEND);
638		glColor4f (0,0,0,0.5);
639		GL_DrawAliasShadow (paliashdr, lastposenum);
640		glEnable (GL_TEXTURE_2D);
641		glDisable (GL_BLEND);
642		glColor4f (1,1,1,1);
643		glPopMatrix ();
644	}
645
646}
647
648//==================================================================================
649
650/*
651=============
652R_DrawEntitiesOnList
653=============
654*/
655void R_DrawEntitiesOnList (void)
656{
657	int		i;
658
659	if (!r_drawentities.value)
660		return;
661
662	// draw sprites seperately, because of alpha blending
663	for (i=0 ; i<cl_numvisedicts ; i++)
664	{
665		currententity = &cl_visedicts[i];
666
667		switch (currententity->model->type)
668		{
669		case mod_alias:
670			R_DrawAliasModel (currententity);
671			break;
672
673		case mod_brush:
674			R_DrawBrushModel (currententity);
675			break;
676
677		default:
678			break;
679		}
680	}
681
682	for (i=0 ; i<cl_numvisedicts ; i++)
683	{
684		currententity = &cl_visedicts[i];
685
686		switch (currententity->model->type)
687		{
688		case mod_sprite:
689			R_DrawSpriteModel (currententity);
690			break;
691
692		default :
693			break;
694		}
695	}
696}
697
698/*
699=============
700R_DrawViewModel
701=============
702*/
703void R_DrawViewModel (void)
704{
705	float		ambient[4], diffuse[4];
706	int			j;
707	int			lnum;
708	vec3_t		dist;
709	float		add;
710	dlight_t	*dl;
711	int			ambientlight, shadelight;
712
713	if (!r_drawviewmodel.value || !Cam_DrawViewModel())
714		return;
715
716	if (envmap)
717		return;
718
719	if (!r_drawentities.value)
720		return;
721
722	if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
723		return;
724
725	if (cl.stats[STAT_HEALTH] <= 0)
726		return;
727
728	currententity = &cl.viewent;
729	if (!currententity->model)
730		return;
731
732	j = R_LightPoint (currententity->origin);
733
734	if (j < 24)
735		j = 24;		// allways give some light on gun
736	ambientlight = j;
737	shadelight = j;
738
739// add dynamic lights
740	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
741	{
742		dl = &cl_dlights[lnum];
743		if (!dl->radius)
744			continue;
745		if (!dl->radius)
746			continue;
747		if (dl->die < cl.time)
748			continue;
749
750		VectorSubtract (currententity->origin, dl->origin, dist);
751		add = dl->radius - Length(dist);
752		if (add > 0)
753			ambientlight += add;
754	}
755
756	ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128;
757	diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128;
758
759	// hack the depth range to prevent view model from poking into walls
760#ifdef USE_OPENGLES
761	glDepthRangef(gldepthmin, gldepthmin + 0.3f*(gldepthmax-gldepthmin));
762	R_DrawAliasModel (currententity);
763	glDepthRangef(gldepthmin, gldepthmax);
764#else
765	glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
766	R_DrawAliasModel (currententity);
767	glDepthRange (gldepthmin, gldepthmax);
768#endif
769}
770
771
772/*
773============
774R_PolyBlend
775============
776*/
777void R_PolyBlend (void)
778{
779	if (!gl_polyblend.value)
780		return;
781	if (!v_blend[3])
782		return;
783
784//Con_Printf("R_PolyBlend(): %4.2f %4.2f %4.2f %4.2f\n",v_blend[0], v_blend[1],	v_blend[2],	v_blend[3]);
785
786 	GL_DisableMultitexture();
787
788	glDisable (GL_ALPHA_TEST);
789	glEnable (GL_BLEND);
790	glDisable (GL_DEPTH_TEST);
791	glDisable (GL_TEXTURE_2D);
792
793    glLoadIdentity ();
794
795    glRotatef (-90,  1, 0, 0);	    // put Z going up
796    glRotatef (90,  0, 0, 1);	    // put Z going up
797
798	glColor4fv (v_blend);
799
800#ifdef USE_OPENGLES
801	// !!! Implement this
802#else
803	glBegin (GL_QUADS);
804
805	glVertex3f (10, 100, 100);
806	glVertex3f (10, -100, 100);
807	glVertex3f (10, -100, -100);
808	glVertex3f (10, 100, -100);
809	glEnd ();
810#endif
811
812	glDisable (GL_BLEND);
813	glEnable (GL_TEXTURE_2D);
814	glEnable (GL_ALPHA_TEST);
815}
816
817
818int SignbitsForPlane (mplane_t *out)
819{
820	int	bits, j;
821
822	// for fast box on planeside test
823
824	bits = 0;
825	for (j=0 ; j<3 ; j++)
826	{
827		if (out->normal[j] < 0)
828			bits |= 1<<j;
829	}
830	return bits;
831}
832
833
834void R_SetFrustum (void)
835{
836	int		i;
837
838	if (r_refdef.fov_x == 90)
839	{
840		// front side is visible
841
842		VectorAdd (vpn, vright, frustum[0].normal);
843		VectorSubtract (vpn, vright, frustum[1].normal);
844
845		VectorAdd (vpn, vup, frustum[2].normal);
846		VectorSubtract (vpn, vup, frustum[3].normal);
847	}
848	else
849	{
850
851		// rotate VPN right by FOV_X/2 degrees
852		RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
853		// rotate VPN left by FOV_X/2 degrees
854		RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
855		// rotate VPN up by FOV_X/2 degrees
856		RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
857		// rotate VPN down by FOV_X/2 degrees
858		RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
859	}
860
861	for (i=0 ; i<4 ; i++)
862	{
863		frustum[i].type = PLANE_ANYZ;
864		frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
865		frustum[i].signbits = SignbitsForPlane (&frustum[i]);
866	}
867}
868
869
870
871/*
872===============
873R_SetupFrame
874===============
875*/
876void R_SetupFrame (void)
877{
878// don't allow cheats in multiplayer
879	r_fullbright.value = 0;
880	r_lightmap.value = 0;
881	if (!atoi(Info_ValueForKey(cl.serverinfo, "watervis")))
882		r_wateralpha.value = 1;
883
884	R_AnimateLight ();
885
886	r_framecount++;
887
888// build the transformation matrix for the given view angles
889	VectorCopy (r_refdef.vieworg, r_origin);
890
891	AngleVectors (r_refdef.viewangles, vpn, vright, vup);
892
893// current viewleaf
894	r_oldviewleaf = r_viewleaf;
895	r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
896
897	V_SetContentsColor (r_viewleaf->contents);
898	V_CalcBlend ();
899
900	r_cache_thrash = false;
901
902	c_brush_polys = 0;
903	c_alias_polys = 0;
904
905}
906
907#ifdef USE_OPENGLES
908
909void MYgluPerspective( float fovy, float aspect,
910		     float zNear, float zFar )
911{
912   float xmin, xmax, ymin, ymax;
913
914   ymax = zNear * tan( fovy * M_PI / 360.0f );
915   ymin = -ymax;
916
917   xmin = ymin * aspect;
918   xmax = ymax * aspect;
919
920   glFrustumf( xmin, xmax, ymin, ymax, zNear, zFar );
921}
922
923#else
924
925void MYgluPerspective( GLdouble fovy, GLdouble aspect,
926		     GLdouble zNear, GLdouble zFar )
927{
928   GLdouble xmin, xmax, ymin, ymax;
929
930   ymax = zNear * tan( fovy * M_PI / 360.0 );
931   ymin = -ymax;
932
933   xmin = ymin * aspect;
934   xmax = ymax * aspect;
935
936   glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
937}
938#endif
939
940/*
941=============
942R_SetupGL
943=============
944*/
945void R_SetupGL (void)
946{
947	float	screenaspect;
948	extern	int glwidth, glheight;
949	int		x, x2, y2, y, w, h;
950
951	//
952	// set up viewpoint
953	//
954	glMatrixMode(GL_PROJECTION);
955    glLoadIdentity ();
956	x = r_refdef.vrect.x * glwidth/vid.width;
957	x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width;
958	y = (vid.height-r_refdef.vrect.y) * glheight/vid.height;
959	y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height;
960
961	// fudge around because of frac screen scale
962	if (x > 0)
963		x--;
964	if (x2 < glwidth)
965		x2++;
966	if (y2 < 0)
967		y2--;
968	if (y < glheight)
969		y++;
970
971	w = x2 - x;
972	h = y - y2;
973
974	if (envmap)
975	{
976		x = y2 = 0;
977		w = h = 256;
978	}
979
980	glViewport (glx + x, gly + y2, w, h);
981    screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height;
982//	yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI;
983//	yfov = (2.0 * tan (scr_fov.value/360*M_PI)) / screenaspect;
984//	yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*(scr_fov.value*2)/M_PI;
985//    MYgluPerspective (yfov,  screenaspect,  4,  4096);
986    MYgluPerspective (r_refdef.fov_y,  screenaspect,  4,  4096);
987
988	if (mirror)
989	{
990		if (mirror_plane->normal[2])
991			glScalef (1, -1, 1);
992		else
993			glScalef (-1, 1, 1);
994		glCullFace(GL_BACK);
995	}
996	else
997		glCullFace(GL_FRONT);
998
999	glMatrixMode(GL_MODELVIEW);
1000    glLoadIdentity ();
1001
1002    glRotatef (-90,  1, 0, 0);	    // put Z going up
1003    glRotatef (90,  0, 0, 1);	    // put Z going up
1004    glRotatef (-r_refdef.viewangles[2],  1, 0, 0);
1005    glRotatef (-r_refdef.viewangles[0],  0, 1, 0);
1006    glRotatef (-r_refdef.viewangles[1],  0, 0, 1);
1007    glTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);
1008
1009#ifdef USE_OPENGLES
1010	glGetIntegerv (MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES, (GLint*) r_world_matrix);
1011#else
1012	glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);
1013#endif
1014
1015	//
1016	// set drawing parms
1017	//
1018	if (gl_cull.value)
1019		glEnable(GL_CULL_FACE);
1020	else
1021		glDisable(GL_CULL_FACE);
1022
1023	glDisable(GL_BLEND);
1024	glDisable(GL_ALPHA_TEST);
1025	glEnable(GL_DEPTH_TEST);
1026}
1027
1028/*
1029================
1030R_RenderScene
1031
1032r_refdef must be set before the first call
1033================
1034*/
1035void R_RenderScene (void)
1036{
1037	R_SetupFrame ();
1038
1039	R_SetFrustum ();
1040
1041	R_SetupGL ();
1042
1043	R_MarkLeaves ();	// done here so we know if we're in water
1044
1045	R_DrawWorld ();		// adds static entities to the list
1046
1047	S_ExtraUpdate ();	// don't let sound get messed up if going slow
1048
1049	R_DrawEntitiesOnList ();
1050
1051	GL_DisableMultitexture();
1052
1053	R_RenderDlights ();
1054
1055	R_DrawParticles ();
1056
1057#ifdef GLTEST
1058	Test_Draw ();
1059#endif
1060
1061}
1062
1063
1064/*
1065=============
1066R_Clear
1067=============
1068*/
1069void R_Clear (void)
1070{
1071	if (r_mirroralpha.value != 1.0)
1072	{
1073		if (gl_clear.value)
1074			glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1075		else
1076			glClear (GL_DEPTH_BUFFER_BIT);
1077		gldepthmin = 0;
1078		gldepthmax = 0.5;
1079		glDepthFunc (GL_LEQUAL);
1080	}
1081	else if (gl_ztrick.value)
1082	{
1083		static int trickframe;
1084
1085		if (gl_clear.value)
1086			glClear (GL_COLOR_BUFFER_BIT);
1087
1088		trickframe++;
1089		if (trickframe & 1)
1090		{
1091			gldepthmin = 0;
1092			gldepthmax = 0.49999;
1093			glDepthFunc (GL_LEQUAL);
1094		}
1095		else
1096		{
1097			gldepthmin = 1;
1098			gldepthmax = 0.5;
1099			glDepthFunc (GL_GEQUAL);
1100		}
1101	}
1102	else
1103	{
1104		if (gl_clear.value)
1105			glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1106		else
1107			glClear (GL_DEPTH_BUFFER_BIT);
1108		gldepthmin = 0;
1109		gldepthmax = 1;
1110		glDepthFunc (GL_LEQUAL);
1111	}
1112
1113#ifdef USE_OPENGLES
1114	glDepthRangef (gldepthmin, gldepthmax);
1115#else
1116	glDepthRange (gldepthmin, gldepthmax);
1117#endif
1118}
1119
1120#if 0 //!!! FIXME, Zoid, mirror is disabled for now
1121/*
1122=============
1123R_Mirror
1124=============
1125*/
1126void R_Mirror (void)
1127{
1128	float		d;
1129	msurface_t	*s;
1130	entity_t	*ent;
1131
1132	if (!mirror)
1133		return;
1134
1135	memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix));
1136
1137	d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist;
1138	VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg);
1139
1140	d = DotProduct (vpn, mirror_plane->normal);
1141	VectorMA (vpn, -2*d, mirror_plane->normal, vpn);
1142
1143	r_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180;
1144	r_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180;
1145	r_refdef.viewangles[2] = -r_refdef.viewangles[2];
1146
1147	ent = &cl_entities[cl.viewentity];
1148	if (cl_numvisedicts < MAX_VISEDICTS)
1149	{
1150		cl_visedicts[cl_numvisedicts] = ent;
1151		cl_numvisedicts++;
1152	}
1153
1154	gldepthmin = 0.5;
1155	gldepthmax = 1;
1156	glDepthRange (gldepthmin, gldepthmax);
1157	glDepthFunc (GL_LEQUAL);
1158
1159	R_RenderScene ();
1160	R_DrawWaterSurfaces ();
1161
1162
1163	gldepthmin = 0;
1164	gldepthmax = 0.5;
1165	glDepthRange (gldepthmin, gldepthmax);
1166	glDepthFunc (GL_LEQUAL);
1167
1168	// blend on top
1169	glEnable (GL_BLEND);
1170	glMatrixMode(GL_PROJECTION);
1171	if (mirror_plane->normal[2])
1172		glScalef (1,-1,1);
1173	else
1174		glScalef (-1,1,1);
1175	glCullFace(GL_FRONT);
1176	glMatrixMode(GL_MODELVIEW);
1177
1178	glLoadMatrixf (r_base_world_matrix);
1179
1180	glColor4f (1,1,1,r_mirroralpha.value);
1181	s = cl.worldmodel->textures[mirrortexturenum]->texturechain;
1182	for ( ; s ; s=s->texturechain)
1183		R_RenderBrushPoly (s);
1184	cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL;
1185	glDisable (GL_BLEND);
1186	glColor4f (1,1,1,1);
1187}
1188#endif
1189
1190/*
1191================
1192R_RenderView
1193
1194r_refdef must be set before the first call
1195================
1196*/
1197void R_RenderView (void)
1198{
1199	double	time1 = 0, time2;
1200
1201	if (r_norefresh.value)
1202		return;
1203
1204	if (!r_worldentity.model || !cl.worldmodel)
1205		Sys_Error ("R_RenderView: NULL worldmodel");
1206
1207	if (r_speeds.value)
1208	{
1209		glFinish ();
1210		time1 = Sys_DoubleTime ();
1211		c_brush_polys = 0;
1212		c_alias_polys = 0;
1213	}
1214
1215	mirror = false;
1216
1217	if (gl_finish.value)
1218		glFinish ();
1219
1220	R_Clear ();
1221
1222	// render normal view
1223	R_RenderScene ();
1224	R_DrawViewModel ();
1225	R_DrawWaterSurfaces ();
1226
1227	// render mirror view
1228//	R_Mirror ();
1229
1230	R_PolyBlend ();
1231
1232	if (r_speeds.value)
1233	{
1234//		glFinish ();
1235		time2 = Sys_DoubleTime ();
1236		Con_Printf ("%3i ms  %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys);
1237	}
1238}
1239