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_surf.c: surface-related refresh code
21
22#include "quakedef.h"
23
24int			skytexturenum;
25
26#ifndef GL_RGBA4
27#define	GL_RGBA4	0
28#endif
29
30
31int		lightmap_bytes;		// 1, 2, or 4
32
33int		lightmap_textures;
34
35unsigned		blocklights[18*18];
36
37#define	BLOCK_WIDTH		128
38#define	BLOCK_HEIGHT	128
39
40#define	MAX_LIGHTMAPS	64
41int			active_lightmaps;
42
43typedef struct glRect_s {
44	unsigned char l,t,w,h;
45} glRect_t;
46
47glpoly_t	*lightmap_polys[MAX_LIGHTMAPS];
48qboolean	lightmap_modified[MAX_LIGHTMAPS];
49glRect_t	lightmap_rectchange[MAX_LIGHTMAPS];
50
51int			allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
52
53// the lightmap texture data needs to be kept in
54// main memory so texsubimage can update properly
55byte		lightmaps[4*MAX_LIGHTMAPS*BLOCK_WIDTH*BLOCK_HEIGHT];
56
57// For gl_texsort 0
58msurface_t  *skychain = NULL;
59msurface_t  *waterchain = NULL;
60
61void R_RenderDynamicLightmaps (msurface_t *fa);
62
63/*
64===============
65R_AddDynamicLights
66===============
67*/
68void R_AddDynamicLights (msurface_t *surf)
69{
70	int			lnum;
71	int			sd, td;
72	float		dist, rad, minlight;
73	vec3_t		impact, local;
74	int			s, t;
75	int			i;
76	int			smax, tmax;
77	mtexinfo_t	*tex;
78
79	smax = (surf->extents[0]>>4)+1;
80	tmax = (surf->extents[1]>>4)+1;
81	tex = surf->texinfo;
82
83	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
84	{
85		if ( !(surf->dlightbits & (1<<lnum) ) )
86			continue;		// not lit by this light
87
88		rad = cl_dlights[lnum].radius;
89		dist = DotProduct (cl_dlights[lnum].origin, surf->plane->normal) -
90				surf->plane->dist;
91		rad -= fabs(dist);
92		minlight = cl_dlights[lnum].minlight;
93		if (rad < minlight)
94			continue;
95		minlight = rad - minlight;
96
97		for (i=0 ; i<3 ; i++)
98		{
99			impact[i] = cl_dlights[lnum].origin[i] -
100					surf->plane->normal[i]*dist;
101		}
102
103		local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
104		local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
105
106		local[0] -= surf->texturemins[0];
107		local[1] -= surf->texturemins[1];
108
109		for (t = 0 ; t<tmax ; t++)
110		{
111			td = local[1] - t*16;
112			if (td < 0)
113				td = -td;
114			for (s=0 ; s<smax ; s++)
115			{
116				sd = local[0] - s*16;
117				if (sd < 0)
118					sd = -sd;
119				if (sd > td)
120					dist = sd + (td>>1);
121				else
122					dist = td + (sd>>1);
123				if (dist < minlight)
124					blocklights[t*smax + s] += (rad - dist)*256;
125			}
126		}
127	}
128}
129
130
131/*
132===============
133R_BuildLightMap
134
135Combine and scale multiple lightmaps into the 8.8 format in blocklights
136===============
137*/
138void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
139{
140	int			smax, tmax;
141	int			t;
142	int			i, j, size;
143	byte		*lightmap;
144	unsigned	scale;
145	int			maps;
146	unsigned	*bl;
147
148	surf->cached_dlight = (surf->dlightframe == r_framecount);
149
150	smax = (surf->extents[0]>>4)+1;
151	tmax = (surf->extents[1]>>4)+1;
152	size = smax*tmax;
153	lightmap = surf->samples;
154
155// set to full bright if no light data
156	if (/* r_fullbright.value || */ !cl.worldmodel->lightdata)
157	{
158		for (i=0 ; i<size ; i++)
159			blocklights[i] = 255*256;
160		goto store;
161	}
162
163// clear to no light
164	for (i=0 ; i<size ; i++)
165		blocklights[i] = 0;
166
167// add all the lightmaps
168	if (lightmap)
169		for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
170			 maps++)
171		{
172			scale = d_lightstylevalue[surf->styles[maps]];
173			surf->cached_light[maps] = scale;	// 8.8 fraction
174			for (i=0 ; i<size ; i++)
175				blocklights[i] += lightmap[i] * scale;
176			lightmap += size;	// skip to next lightmap
177		}
178
179// add all the dynamic lights
180	if (surf->dlightframe == r_framecount)
181		R_AddDynamicLights (surf);
182
183// bound, invert, and shift
184store:
185	switch (gl_lightmap_format)
186	{
187	case GL_RGBA:
188		stride -= (smax<<2);
189		bl = blocklights;
190		for (i=0 ; i<tmax ; i++, dest += stride)
191		{
192			for (j=0 ; j<smax ; j++)
193			{
194				t = *bl++;
195				t >>= 7;
196				if (t > 255)
197					t = 255;
198				dest[3] = 255-t;
199				dest += 4;
200			}
201		}
202		break;
203	case GL_ALPHA:
204	case GL_LUMINANCE:
205	case GL_INTENSITY:
206		bl = blocklights;
207		for (i=0 ; i<tmax ; i++, dest += stride)
208		{
209			for (j=0 ; j<smax ; j++)
210			{
211				t = *bl++;
212				t >>= 7;
213				if (t > 255)
214					t = 255;
215				dest[j] = 255-t;
216			}
217		}
218		break;
219	default:
220		Sys_Error ("Bad lightmap format");
221	}
222}
223
224
225/*
226===============
227R_TextureAnimation
228
229Returns the proper texture for a given time and base texture
230===============
231*/
232texture_t *R_TextureAnimation (texture_t *base)
233{
234	int		reletive;
235	int		count;
236
237	if (currententity->frame)
238	{
239		if (base->alternate_anims)
240			base = base->alternate_anims;
241	}
242
243	if (!base->anim_total)
244		return base;
245
246	reletive = (int)(cl.time*10) % base->anim_total;
247
248	count = 0;
249	while (base->anim_min > reletive || base->anim_max <= reletive)
250	{
251		base = base->anim_next;
252		if (!base)
253			Sys_Error ("R_TextureAnimation: broken cycle");
254		if (++count > 100)
255			Sys_Error ("R_TextureAnimation: infinite cycle");
256	}
257
258	return base;
259}
260
261
262/*
263=============================================================
264
265	BRUSH MODELS
266
267=============================================================
268*/
269
270
271extern	int		solidskytexture;
272extern	int		alphaskytexture;
273extern	float	speedscale;		// for top sky and bottom sky
274
275void DrawGLWaterPoly (glpoly_t *p);
276void DrawGLWaterPolyLightmap (glpoly_t *p);
277
278#ifdef _WIN32
279lpMTexFUNC qglMTexCoord2fSGIS = NULL;
280lpSelTexFUNC qglSelectTextureSGIS = NULL;
281#endif
282
283qboolean mtexenabled = false;
284
285void GL_SelectTexture (GLenum target);
286
287void GL_DisableMultitexture(void)
288{
289	if (mtexenabled) {
290		glDisable(GL_TEXTURE_2D);
291		GL_SelectTexture(TEXTURE0_SGIS);
292		mtexenabled = false;
293	}
294}
295
296void GL_EnableMultitexture(void)
297{
298	if (gl_mtexable) {
299		GL_SelectTexture(TEXTURE1_SGIS);
300		glEnable(GL_TEXTURE_2D);
301		mtexenabled = true;
302	}
303}
304
305#ifndef _WIN32
306/*
307================
308R_DrawSequentialPoly
309
310Systems that have fast state and texture changes can
311just do everything as it passes with no need to sort
312================
313*/
314void R_DrawSequentialPoly (msurface_t *s)
315{
316	glpoly_t	*p;
317	float		*v;
318	int			i;
319	texture_t	*t;
320
321	//
322	// normal lightmaped poly
323	//
324//	if ((!(s->flags & (SURF_DRAWSKY|SURF_DRAWTURB)))
325//		&& ((r_viewleaf->contents!=CONTENTS_EMPTY && (s->flags & SURF_UNDERWATER)) ||
326//		(r_viewleaf->contents==CONTENTS_EMPTY && !(s->flags & SURF_UNDERWATER))))
327#if 0
328	if (0)
329	{
330		p = s->polys;
331
332		t = R_TextureAnimation (s->texinfo->texture);
333		GL_Bind (t->gl_texturenum);
334		glBegin (GL_POLYGON);
335		v = p->verts[0];
336		for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
337		{
338			glTexCoord2f (v[3], v[4]);
339			glVertex3fv (v);
340		}
341		glEnd ();
342
343		GL_Bind (lightmap_textures + s->lightmaptexturenum);
344		glEnable (GL_BLEND);
345		glBegin (GL_POLYGON);
346		v = p->verts[0];
347		for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
348		{
349			glTexCoord2f (v[5], v[6]);
350			glVertex3fv (v);
351		}
352		glEnd ();
353
354		glDisable (GL_BLEND);
355
356		return;
357	}
358#endif
359
360	//
361	// subdivided water surface warp
362	//
363	if (s->flags & SURF_DRAWTURB)
364	{
365		GL_Bind (s->texinfo->texture->gl_texturenum);
366		EmitWaterPolys (s);
367		return;
368	}
369
370	//
371	// subdivided sky warp
372	//
373	if (s->flags & SURF_DRAWSKY)
374	{
375		GL_Bind (solidskytexture);
376		speedscale = realtime*8;
377		speedscale -= (int)speedscale;
378
379		EmitSkyPolys (s);
380
381		glEnable (GL_BLEND);
382		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
383		GL_Bind (alphaskytexture);
384		speedscale = realtime*16;
385		speedscale -= (int)speedscale;
386		EmitSkyPolys (s);
387		if (gl_lightmap_format == GL_LUMINANCE)
388			glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
389
390		glDisable (GL_BLEND);
391	}
392
393	//
394	// underwater warped with lightmap
395	//
396	p = s->polys;
397
398	t = R_TextureAnimation (s->texinfo->texture);
399	GL_Bind (t->gl_texturenum);
400	DrawGLWaterPoly (p);
401
402	GL_Bind (lightmap_textures + s->lightmaptexturenum);
403	glEnable (GL_BLEND);
404	DrawGLWaterPolyLightmap (p);
405	glDisable (GL_BLEND);
406}
407#else
408/*
409================
410R_DrawSequentialPoly
411
412Systems that have fast state and texture changes can
413just do everything as it passes with no need to sort
414================
415*/
416void R_DrawSequentialPoly (msurface_t *s)
417{
418	glpoly_t	*p;
419	float		*v;
420	int			i;
421	texture_t	*t;
422	vec3_t		nv, dir;
423	float		ss, ss2, length;
424	float		s1, t1;
425	glRect_t	*theRect;
426
427	//
428	// normal lightmaped poly
429	//
430
431	if (! (s->flags & (SURF_DRAWSKY|SURF_DRAWTURB|SURF_UNDERWATER) ) )
432	{
433		R_RenderDynamicLightmaps (s);
434		if (gl_mtexable) {
435			p = s->polys;
436
437			t = R_TextureAnimation (s->texinfo->texture);
438			// Binds world to texture env 0
439			GL_SelectTexture(TEXTURE0_SGIS);
440			GL_Bind (t->gl_texturenum);
441			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
442			// Binds lightmap to texenv 1
443			GL_EnableMultitexture(); // Same as SelectTexture (TEXTURE1)
444			GL_Bind (lightmap_textures + s->lightmaptexturenum);
445			i = s->lightmaptexturenum;
446			if (lightmap_modified[i])
447			{
448				lightmap_modified[i] = false;
449				theRect = &lightmap_rectchange[i];
450				glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
451					BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
452					lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
453				theRect->l = BLOCK_WIDTH;
454				theRect->t = BLOCK_HEIGHT;
455				theRect->h = 0;
456				theRect->w = 0;
457			}
458			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
459			glBegin(GL_POLYGON);
460			v = p->verts[0];
461			for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
462			{
463				qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]);
464				qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);
465				glVertex3fv (v);
466			}
467			glEnd ();
468			return;
469		} else {
470			p = s->polys;
471
472			t = R_TextureAnimation (s->texinfo->texture);
473			GL_Bind (t->gl_texturenum);
474			glBegin (GL_POLYGON);
475			v = p->verts[0];
476			for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
477			{
478				glTexCoord2f (v[3], v[4]);
479				glVertex3fv (v);
480			}
481			glEnd ();
482
483			GL_Bind (lightmap_textures + s->lightmaptexturenum);
484			glEnable (GL_BLEND);
485			glBegin (GL_POLYGON);
486			v = p->verts[0];
487			for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
488			{
489				glTexCoord2f (v[5], v[6]);
490				glVertex3fv (v);
491			}
492			glEnd ();
493
494			glDisable (GL_BLEND);
495		}
496
497		return;
498	}
499
500	//
501	// subdivided water surface warp
502	//
503
504	if (s->flags & SURF_DRAWTURB)
505	{
506		GL_DisableMultitexture();
507		GL_Bind (s->texinfo->texture->gl_texturenum);
508		EmitWaterPolys (s);
509		return;
510	}
511
512	//
513	// subdivided sky warp
514	//
515	if (s->flags & SURF_DRAWSKY)
516	{
517		GL_DisableMultitexture();
518		GL_Bind (solidskytexture);
519		speedscale = realtime*8;
520		speedscale -= (int)speedscale & ~127;
521
522		EmitSkyPolys (s);
523
524		glEnable (GL_BLEND);
525		GL_Bind (alphaskytexture);
526		speedscale = realtime*16;
527		speedscale -= (int)speedscale & ~127;
528		EmitSkyPolys (s);
529
530		glDisable (GL_BLEND);
531		return;
532	}
533
534	//
535	// underwater warped with lightmap
536	//
537	R_RenderDynamicLightmaps (s);
538	if (gl_mtexable) {
539		p = s->polys;
540
541		t = R_TextureAnimation (s->texinfo->texture);
542		GL_SelectTexture(TEXTURE0_SGIS);
543		GL_Bind (t->gl_texturenum);
544		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
545		GL_EnableMultitexture();
546		GL_Bind (lightmap_textures + s->lightmaptexturenum);
547		i = s->lightmaptexturenum;
548		if (lightmap_modified[i])
549		{
550			lightmap_modified[i] = false;
551			theRect = &lightmap_rectchange[i];
552			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
553				BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
554				lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
555			theRect->l = BLOCK_WIDTH;
556			theRect->t = BLOCK_HEIGHT;
557			theRect->h = 0;
558			theRect->w = 0;
559		}
560		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
561		glBegin (GL_TRIANGLE_FAN);
562		v = p->verts[0];
563		for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
564		{
565			qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]);
566			qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);
567
568			nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
569			nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
570			nv[2] = v[2];
571
572			glVertex3fv (nv);
573		}
574		glEnd ();
575
576	} else {
577		p = s->polys;
578
579		t = R_TextureAnimation (s->texinfo->texture);
580		GL_Bind (t->gl_texturenum);
581		DrawGLWaterPoly (p);
582
583		GL_Bind (lightmap_textures + s->lightmaptexturenum);
584		glEnable (GL_BLEND);
585		DrawGLWaterPolyLightmap (p);
586		glDisable (GL_BLEND);
587	}
588}
589#endif
590
591
592/*
593================
594DrawGLWaterPoly
595
596Warp the vertex coordinates
597================
598*/
599void DrawGLWaterPoly (glpoly_t *p)
600{
601	int		i;
602	float	*v;
603	vec3_t	nv;
604
605	GL_DisableMultitexture();
606
607#ifdef USE_OPENGLES
608	// !!! Implement this.
609#else
610	glBegin (GL_TRIANGLE_FAN);
611	v = p->verts[0];
612	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
613	{
614		glTexCoord2f (v[3], v[4]);
615
616		nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
617		nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
618		nv[2] = v[2];
619
620		glVertex3fv (nv);
621	}
622	glEnd ();
623#endif
624}
625
626void DrawGLWaterPolyLightmap (glpoly_t *p)
627{
628	int		i;
629	float	*v;
630	vec3_t	nv;
631
632	GL_DisableMultitexture();
633
634#ifdef USE_OPENGLES
635	// !!! Implement this.
636#else
637	glBegin (GL_TRIANGLE_FAN);
638	v = p->verts[0];
639	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
640	{
641		glTexCoord2f (v[5], v[6]);
642
643		nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
644		nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
645		nv[2] = v[2];
646
647		glVertex3fv (nv);
648	}
649	glEnd ();
650#endif
651}
652
653/*
654================
655DrawGLPoly
656================
657*/
658void DrawGLPoly (glpoly_t *p)
659{
660	int		i;
661	float	*v;
662
663#ifdef USE_OPENGLES
664	// !!! Implement this.
665#else
666	glBegin (GL_POLYGON);
667	v = p->verts[0];
668	for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
669	{
670		glTexCoord2f (v[3], v[4]);
671		glVertex3fv (v);
672	}
673	glEnd ();
674#endif
675}
676
677
678/*
679================
680R_BlendLightmaps
681================
682*/
683void R_BlendLightmaps (void)
684{
685	int			i, j;
686	glpoly_t	*p;
687	float		*v;
688	glRect_t	*theRect;
689
690#if 0
691	if (r_fullbright.value)
692		return;
693#endif
694	if (!gl_texsort.value)
695		return;
696
697	glDepthMask (0);		// don't bother writing Z
698
699	if (gl_lightmap_format == GL_LUMINANCE)
700		glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
701	else if (gl_lightmap_format == GL_INTENSITY)
702	{
703		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
704		glColor4f (0,0,0,1);
705		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
706	}
707
708	if (!r_lightmap.value)
709	{
710		glEnable (GL_BLEND);
711	}
712
713	for (i=0 ; i<MAX_LIGHTMAPS ; i++)
714	{
715		p = lightmap_polys[i];
716		if (!p)
717			continue;
718		GL_Bind(lightmap_textures+i);
719		if (lightmap_modified[i])
720		{
721			lightmap_modified[i] = false;
722			theRect = &lightmap_rectchange[i];
723//			theRect->l = 0;
724//			theRect->t = 0;
725//			theRect->w = BLOCK_WIDTH;
726//			theRect->h = BLOCK_HEIGHT;
727//			glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes
728//			, BLOCK_WIDTH, BLOCK_HEIGHT, 0,
729//			gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
730//			glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes
731//				, BLOCK_WIDTH, theRect->h, 0,
732//				gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+(i*BLOCK_HEIGHT+theRect->t)*BLOCK_WIDTH*lightmap_bytes);
733			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
734				BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
735				lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
736			theRect->l = BLOCK_WIDTH;
737			theRect->t = BLOCK_HEIGHT;
738			theRect->h = 0;
739			theRect->w = 0;
740		}
741		for ( ; p ; p=p->chain)
742		{
743//			if (p->flags & SURF_UNDERWATER)
744//				DrawGLWaterPolyLightmap (p);
745			if (((r_viewleaf->contents==CONTENTS_EMPTY && (p->flags & SURF_UNDERWATER)) ||
746				(r_viewleaf->contents!=CONTENTS_EMPTY && !(p->flags & SURF_UNDERWATER)))
747				&& !(p->flags & SURF_DONTWARP))
748				DrawGLWaterPolyLightmap (p);
749			else
750			{
751#ifdef USE_OPENGLES
752	// !!! Implement this.
753#else
754				glBegin (GL_POLYGON);
755				v = p->verts[0];
756				for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
757				{
758					glTexCoord2f (v[5], v[6]);
759					glVertex3fv (v);
760				}
761				glEnd ();
762#endif
763			}
764		}
765	}
766
767	glDisable (GL_BLEND);
768	if (gl_lightmap_format == GL_LUMINANCE)
769		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
770	else if (gl_lightmap_format == GL_INTENSITY)
771	{
772		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
773		glColor4f (1,1,1,1);
774	}
775
776	glDepthMask (1);		// back to normal Z buffering
777}
778
779/*
780================
781R_RenderBrushPoly
782================
783*/
784void R_RenderBrushPoly (msurface_t *fa)
785{
786	texture_t	*t;
787	byte		*base;
788	int			maps;
789	glRect_t    *theRect;
790	int smax, tmax;
791
792	c_brush_polys++;
793
794	if (fa->flags & SURF_DRAWSKY)
795	{	// warp texture, no lightmaps
796		EmitBothSkyLayers (fa);
797		return;
798	}
799
800	t = R_TextureAnimation (fa->texinfo->texture);
801	GL_Bind (t->gl_texturenum);
802
803	if (fa->flags & SURF_DRAWTURB)
804	{	// warp texture, no lightmaps
805		EmitWaterPolys (fa);
806		return;
807	}
808
809	if (((r_viewleaf->contents==CONTENTS_EMPTY && (fa->flags & SURF_UNDERWATER)) ||
810		(r_viewleaf->contents!=CONTENTS_EMPTY && !(fa->flags & SURF_UNDERWATER)))
811		&& !(fa->flags & SURF_DONTWARP))
812		DrawGLWaterPoly (fa->polys);
813	else
814		DrawGLPoly (fa->polys);
815
816	// add the poly to the proper lightmap chain
817
818	fa->polys->chain = lightmap_polys[fa->lightmaptexturenum];
819	lightmap_polys[fa->lightmaptexturenum] = fa->polys;
820
821	// check for lightmap modification
822	for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;
823		 maps++)
824		if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
825			goto dynamic;
826
827	if (fa->dlightframe == r_framecount	// dynamic this frame
828		|| fa->cached_dlight)			// dynamic previously
829	{
830dynamic:
831		if (r_dynamic.value)
832		{
833			lightmap_modified[fa->lightmaptexturenum] = true;
834			theRect = &lightmap_rectchange[fa->lightmaptexturenum];
835			if (fa->light_t < theRect->t) {
836				if (theRect->h)
837					theRect->h += theRect->t - fa->light_t;
838				theRect->t = fa->light_t;
839			}
840			if (fa->light_s < theRect->l) {
841				if (theRect->w)
842					theRect->w += theRect->l - fa->light_s;
843				theRect->l = fa->light_s;
844			}
845			smax = (fa->extents[0]>>4)+1;
846			tmax = (fa->extents[1]>>4)+1;
847			if ((theRect->w + theRect->l) < (fa->light_s + smax))
848				theRect->w = (fa->light_s-theRect->l)+smax;
849			if ((theRect->h + theRect->t) < (fa->light_t + tmax))
850				theRect->h = (fa->light_t-theRect->t)+tmax;
851			base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
852			base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
853			R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);
854		}
855	}
856}
857
858/*
859================
860R_RenderDynamicLightmaps
861Multitexture
862================
863*/
864void R_RenderDynamicLightmaps (msurface_t *fa)
865{
866	byte		*base;
867	int			maps;
868	glRect_t    *theRect;
869	int smax, tmax;
870
871	c_brush_polys++;
872
873	if (fa->flags & ( SURF_DRAWSKY | SURF_DRAWTURB) )
874		return;
875
876	fa->polys->chain = lightmap_polys[fa->lightmaptexturenum];
877	lightmap_polys[fa->lightmaptexturenum] = fa->polys;
878
879	// check for lightmap modification
880	for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;
881		 maps++)
882		if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
883			goto dynamic;
884
885	if (fa->dlightframe == r_framecount	// dynamic this frame
886		|| fa->cached_dlight)			// dynamic previously
887	{
888dynamic:
889		if (r_dynamic.value)
890		{
891			lightmap_modified[fa->lightmaptexturenum] = true;
892			theRect = &lightmap_rectchange[fa->lightmaptexturenum];
893			if (fa->light_t < theRect->t) {
894				if (theRect->h)
895					theRect->h += theRect->t - fa->light_t;
896				theRect->t = fa->light_t;
897			}
898			if (fa->light_s < theRect->l) {
899				if (theRect->w)
900					theRect->w += theRect->l - fa->light_s;
901				theRect->l = fa->light_s;
902			}
903			smax = (fa->extents[0]>>4)+1;
904			tmax = (fa->extents[1]>>4)+1;
905			if ((theRect->w + theRect->l) < (fa->light_s + smax))
906				theRect->w = (fa->light_s-theRect->l)+smax;
907			if ((theRect->h + theRect->t) < (fa->light_t + tmax))
908				theRect->h = (fa->light_t-theRect->t)+tmax;
909			base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
910			base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
911			R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);
912		}
913	}
914}
915
916/*
917================
918R_MirrorChain
919================
920*/
921void R_MirrorChain (msurface_t *s)
922{
923	if (mirror)
924		return;
925	mirror = true;
926	mirror_plane = s->plane;
927}
928
929
930#if 0
931/*
932================
933R_DrawWaterSurfaces
934================
935*/
936void R_DrawWaterSurfaces (void)
937{
938	int			i;
939	msurface_t	*s;
940	texture_t	*t;
941
942	if (r_wateralpha.value == 1.0)
943		return;
944
945	//
946	// go back to the world matrix
947	//
948    glLoadMatrixf (r_world_matrix);
949
950	glEnable (GL_BLEND);
951	glColor4f (1,1,1,r_wateralpha.value);
952	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
953
954	for (i=0 ; i<cl.worldmodel->numtextures ; i++)
955	{
956		t = cl.worldmodel->textures[i];
957		if (!t)
958			continue;
959		s = t->texturechain;
960		if (!s)
961			continue;
962		if ( !(s->flags & SURF_DRAWTURB) )
963			continue;
964
965		// set modulate mode explicitly
966		GL_Bind (t->gl_texturenum);
967
968		for ( ; s ; s=s->texturechain)
969			R_RenderBrushPoly (s);
970
971		t->texturechain = NULL;
972	}
973
974	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
975
976	glColor4f (1,1,1,1);
977	glDisable (GL_BLEND);
978}
979#else
980/*
981================
982R_DrawWaterSurfaces
983================
984*/
985void R_DrawWaterSurfaces (void)
986{
987	int			i;
988	msurface_t	*s;
989	texture_t	*t;
990
991	if (r_wateralpha.value == 1.0 && gl_texsort.value)
992		return;
993
994	//
995	// go back to the world matrix
996	//
997
998    glLoadMatrixf (r_world_matrix);
999
1000	if (r_wateralpha.value < 1.0) {
1001		glEnable (GL_BLEND);
1002		glColor4f (1,1,1,r_wateralpha.value);
1003		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1004	}
1005
1006	if (!gl_texsort.value) {
1007		if (!waterchain)
1008			return;
1009
1010		for ( s = waterchain ; s ; s=s->texturechain) {
1011			GL_Bind (s->texinfo->texture->gl_texturenum);
1012			EmitWaterPolys (s);
1013		}
1014
1015		waterchain = NULL;
1016	} else {
1017
1018		for (i=0 ; i<cl.worldmodel->numtextures ; i++)
1019		{
1020			t = cl.worldmodel->textures[i];
1021			if (!t)
1022				continue;
1023			s = t->texturechain;
1024			if (!s)
1025				continue;
1026			if ( !(s->flags & SURF_DRAWTURB ) )
1027				continue;
1028
1029			// set modulate mode explicitly
1030
1031			GL_Bind (t->gl_texturenum);
1032
1033			for ( ; s ; s=s->texturechain)
1034				EmitWaterPolys (s);
1035
1036			t->texturechain = NULL;
1037		}
1038
1039	}
1040
1041	if (r_wateralpha.value < 1.0) {
1042		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1043
1044		glColor4f (1,1,1,1);
1045		glDisable (GL_BLEND);
1046	}
1047
1048}
1049
1050#endif
1051
1052/*
1053================
1054DrawTextureChains
1055================
1056*/
1057void DrawTextureChains (void)
1058{
1059	int		i;
1060	msurface_t	*s;
1061	texture_t	*t;
1062
1063	if (!gl_texsort.value) {
1064		GL_DisableMultitexture();
1065
1066		if (skychain) {
1067			R_DrawSkyChain(skychain);
1068			skychain = NULL;
1069		}
1070
1071		return;
1072	}
1073
1074	for (i=0 ; i<cl.worldmodel->numtextures ; i++)
1075	{
1076		t = cl.worldmodel->textures[i];
1077		if (!t)
1078			continue;
1079		s = t->texturechain;
1080		if (!s)
1081			continue;
1082		if (i == skytexturenum)
1083			R_DrawSkyChain (s);
1084		else if (i == mirrortexturenum && r_mirroralpha.value != 1.0)
1085		{
1086			R_MirrorChain (s);
1087			continue;
1088		}
1089		else
1090		{
1091			if ((s->flags & SURF_DRAWTURB) && r_wateralpha.value != 1.0)
1092				continue;	// draw translucent water later
1093			for ( ; s ; s=s->texturechain)
1094				R_RenderBrushPoly (s);
1095		}
1096
1097		t->texturechain = NULL;
1098	}
1099}
1100
1101/*
1102=================
1103R_DrawBrushModel
1104=================
1105*/
1106void R_DrawBrushModel (entity_t *e)
1107{
1108	int			i;
1109	int			k;
1110	vec3_t		mins, maxs;
1111	msurface_t	*psurf;
1112	float		dot;
1113	mplane_t	*pplane;
1114	model_t		*clmodel;
1115	qboolean	rotated;
1116
1117	currententity = e;
1118	currenttexture = -1;
1119
1120	clmodel = e->model;
1121
1122	if (e->angles[0] || e->angles[1] || e->angles[2])
1123	{
1124		rotated = true;
1125		for (i=0 ; i<3 ; i++)
1126		{
1127			mins[i] = e->origin[i] - clmodel->radius;
1128			maxs[i] = e->origin[i] + clmodel->radius;
1129		}
1130	}
1131	else
1132	{
1133		rotated = false;
1134		VectorAdd (e->origin, clmodel->mins, mins);
1135		VectorAdd (e->origin, clmodel->maxs, maxs);
1136	}
1137
1138	if (R_CullBox (mins, maxs))
1139		return;
1140
1141	glColor3f (1,1,1);
1142	memset (lightmap_polys, 0, sizeof(lightmap_polys));
1143
1144	VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
1145	if (rotated)
1146	{
1147		vec3_t	temp;
1148		vec3_t	forward, right, up;
1149
1150		VectorCopy (modelorg, temp);
1151		AngleVectors (e->angles, forward, right, up);
1152		modelorg[0] = DotProduct (temp, forward);
1153		modelorg[1] = -DotProduct (temp, right);
1154		modelorg[2] = DotProduct (temp, up);
1155	}
1156
1157	psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
1158
1159// calculate dynamic lighting for bmodel if it's not an
1160// instanced model
1161	if (clmodel->firstmodelsurface != 0 && !gl_flashblend.value)
1162	{
1163		for (k=0 ; k<MAX_DLIGHTS ; k++)
1164		{
1165			if ((cl_dlights[k].die < cl.time) ||
1166				(!cl_dlights[k].radius))
1167				continue;
1168
1169			R_MarkLights (&cl_dlights[k], 1<<k,
1170				clmodel->nodes + clmodel->hulls[0].firstclipnode);
1171		}
1172	}
1173
1174    glPushMatrix ();
1175e->angles[0] = -e->angles[0];	// stupid quake bug
1176	R_RotateForEntity (e);
1177e->angles[0] = -e->angles[0];	// stupid quake bug
1178
1179	//
1180	// draw texture
1181	//
1182	for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
1183	{
1184	// find which side of the node we are on
1185		pplane = psurf->plane;
1186
1187		dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
1188
1189	// draw the polygon
1190		if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
1191			(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
1192		{
1193			if (gl_texsort.value)
1194				R_RenderBrushPoly (psurf);
1195			else
1196				R_DrawSequentialPoly (psurf);
1197		}
1198	}
1199
1200	R_BlendLightmaps ();
1201
1202	glPopMatrix ();
1203}
1204
1205/*
1206=============================================================
1207
1208	WORLD MODEL
1209
1210=============================================================
1211*/
1212
1213/*
1214================
1215R_RecursiveWorldNode
1216================
1217*/
1218void R_RecursiveWorldNode (mnode_t *node)
1219{
1220	int			c, side;
1221	mplane_t	*plane;
1222	msurface_t	*surf, **mark;
1223	mleaf_t		*pleaf;
1224	double		dot;
1225
1226	if (node->contents == CONTENTS_SOLID)
1227		return;		// solid
1228
1229	if (node->visframe != r_visframecount)
1230		return;
1231	if (R_CullBox (node->minmaxs, node->minmaxs+3))
1232		return;
1233
1234// if a leaf node, draw stuff
1235	if (node->contents < 0)
1236	{
1237		pleaf = (mleaf_t *)node;
1238
1239		mark = pleaf->firstmarksurface;
1240		c = pleaf->nummarksurfaces;
1241
1242		if (c)
1243		{
1244			do
1245			{
1246				(*mark)->visframe = r_framecount;
1247				mark++;
1248			} while (--c);
1249		}
1250
1251	// deal with model fragments in this leaf
1252		if (pleaf->efrags)
1253			R_StoreEfrags (&pleaf->efrags);
1254
1255		return;
1256	}
1257
1258// node is just a decision point, so go down the apropriate sides
1259
1260// find which side of the node we are on
1261	plane = node->plane;
1262
1263	switch (plane->type)
1264	{
1265	case PLANE_X:
1266		dot = modelorg[0] - plane->dist;
1267		break;
1268	case PLANE_Y:
1269		dot = modelorg[1] - plane->dist;
1270		break;
1271	case PLANE_Z:
1272		dot = modelorg[2] - plane->dist;
1273		break;
1274	default:
1275		dot = DotProduct (modelorg, plane->normal) - plane->dist;
1276		break;
1277	}
1278
1279	if (dot >= 0)
1280		side = 0;
1281	else
1282		side = 1;
1283
1284// recurse down the children, front side first
1285	R_RecursiveWorldNode (node->children[side]);
1286
1287// draw stuff
1288	c = node->numsurfaces;
1289
1290	if (c)
1291	{
1292		surf = cl.worldmodel->surfaces + node->firstsurface;
1293
1294		if (dot < 0 -BACKFACE_EPSILON)
1295			side = SURF_PLANEBACK;
1296		else if (dot > BACKFACE_EPSILON)
1297			side = 0;
1298		{
1299			for ( ; c ; c--, surf++)
1300			{
1301				if (surf->visframe != r_framecount)
1302					continue;
1303
1304				// don't backface underwater surfaces, because they warp
1305//				if ( !(surf->flags & SURF_UNDERWATER) && ( (dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) )
1306//					continue;		// wrong side
1307				if ( !(((r_viewleaf->contents==CONTENTS_EMPTY && (surf->flags & SURF_UNDERWATER)) ||
1308					(r_viewleaf->contents!=CONTENTS_EMPTY && !(surf->flags & SURF_UNDERWATER)))
1309					&& !(surf->flags & SURF_DONTWARP)) && ( (dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) )
1310					continue;		// wrong side
1311
1312				// if sorting by texture, just store it out
1313				if (gl_texsort.value)
1314				{
1315					if (!mirror
1316					|| surf->texinfo->texture != cl.worldmodel->textures[mirrortexturenum])
1317					{
1318						surf->texturechain = surf->texinfo->texture->texturechain;
1319						surf->texinfo->texture->texturechain = surf;
1320					}
1321				} else if (surf->flags & SURF_DRAWSKY) {
1322					surf->texturechain = skychain;
1323					skychain = surf;
1324				} else if (surf->flags & SURF_DRAWTURB) {
1325					surf->texturechain = waterchain;
1326					waterchain = surf;
1327				} else
1328					R_DrawSequentialPoly (surf);
1329
1330			}
1331		}
1332
1333	}
1334
1335// recurse down the back side
1336	R_RecursiveWorldNode (node->children[!side]);
1337}
1338
1339
1340
1341/*
1342=============
1343R_DrawWorld
1344=============
1345*/
1346void R_DrawWorld (void)
1347{
1348	entity_t	ent;
1349
1350	memset (&ent, 0, sizeof(ent));
1351	ent.model = cl.worldmodel;
1352
1353	VectorCopy (r_refdef.vieworg, modelorg);
1354
1355	currententity = &ent;
1356	currenttexture = -1;
1357
1358	glColor3f (1,1,1);
1359	memset (lightmap_polys, 0, sizeof(lightmap_polys));
1360#ifdef QUAKE2
1361	R_ClearSkyBox ();
1362#endif
1363
1364	R_RecursiveWorldNode (cl.worldmodel->nodes);
1365
1366		DrawTextureChains ();
1367
1368	R_BlendLightmaps ();
1369
1370#ifdef QUAKE2
1371	R_DrawSkyBox ();
1372#endif
1373}
1374
1375
1376/*
1377===============
1378R_MarkLeaves
1379===============
1380*/
1381void R_MarkLeaves (void)
1382{
1383	byte	*vis;
1384	mnode_t	*node;
1385	int		i;
1386	byte	solid[4096];
1387
1388	if (r_oldviewleaf == r_viewleaf && !r_novis.value)
1389		return;
1390
1391	if (mirror)
1392		return;
1393
1394	r_visframecount++;
1395	r_oldviewleaf = r_viewleaf;
1396
1397	if (r_novis.value)
1398	{
1399		vis = solid;
1400		memset (solid, 0xff, (cl.worldmodel->numleafs+7)>>3);
1401	}
1402	else
1403		vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
1404
1405	for (i=0 ; i<cl.worldmodel->numleafs ; i++)
1406	{
1407		if (vis[i>>3] & (1<<(i&7)))
1408		{
1409			node = (mnode_t *)&cl.worldmodel->leafs[i+1];
1410			do
1411			{
1412				if (node->visframe == r_visframecount)
1413					break;
1414				node->visframe = r_visframecount;
1415				node = node->parent;
1416			} while (node);
1417		}
1418	}
1419}
1420
1421
1422
1423/*
1424=============================================================================
1425
1426  LIGHTMAP ALLOCATION
1427
1428=============================================================================
1429*/
1430
1431// returns a texture number and the position inside it
1432int AllocBlock (int w, int h, int *x, int *y)
1433{
1434	int		i, j;
1435	int		best, best2;
1436	int		texnum;
1437
1438	for (texnum=0 ; texnum<MAX_LIGHTMAPS ; texnum++)
1439	{
1440		best = BLOCK_HEIGHT;
1441
1442		for (i=0 ; i<BLOCK_WIDTH-w ; i++)
1443		{
1444			best2 = 0;
1445
1446			for (j=0 ; j<w ; j++)
1447			{
1448				if (allocated[texnum][i+j] >= best)
1449					break;
1450				if (allocated[texnum][i+j] > best2)
1451					best2 = allocated[texnum][i+j];
1452			}
1453			if (j == w)
1454			{	// this is a valid spot
1455				*x = i;
1456				*y = best = best2;
1457			}
1458		}
1459
1460		if (best + h > BLOCK_HEIGHT)
1461			continue;
1462
1463		for (i=0 ; i<w ; i++)
1464			allocated[texnum][*x + i] = best + h;
1465
1466		return texnum;
1467	}
1468
1469	Sys_Error ("AllocBlock: full");
1470	return 0;
1471}
1472
1473
1474mvertex_t	*r_pcurrentvertbase;
1475model_t		*currentmodel;
1476
1477int	nColinElim;
1478
1479/*
1480================
1481BuildSurfaceDisplayList
1482================
1483*/
1484void BuildSurfaceDisplayList (msurface_t *fa)
1485{
1486	int			i, lindex, lnumverts;
1487	medge_t		*pedges, *r_pedge;
1488	int			vertpage;
1489	float		*vec;
1490	float		s, t;
1491	glpoly_t	*poly;
1492
1493// reconstruct the polygon
1494	pedges = currentmodel->edges;
1495	lnumverts = fa->numedges;
1496	vertpage = 0;
1497
1498	//
1499	// draw texture
1500	//
1501	poly = Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float));
1502	poly->next = fa->polys;
1503	poly->flags = fa->flags;
1504	fa->polys = poly;
1505	poly->numverts = lnumverts;
1506
1507	for (i=0 ; i<lnumverts ; i++)
1508	{
1509		lindex = currentmodel->surfedges[fa->firstedge + i];
1510
1511		if (lindex > 0)
1512		{
1513			r_pedge = &pedges[lindex];
1514			vec = r_pcurrentvertbase[r_pedge->v[0]].position;
1515		}
1516		else
1517		{
1518			r_pedge = &pedges[-lindex];
1519			vec = r_pcurrentvertbase[r_pedge->v[1]].position;
1520		}
1521		s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
1522		s /= fa->texinfo->texture->width;
1523
1524		t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
1525		t /= fa->texinfo->texture->height;
1526
1527		VectorCopy (vec, poly->verts[i]);
1528		poly->verts[i][3] = s;
1529		poly->verts[i][4] = t;
1530
1531		//
1532		// lightmap texture coordinates
1533		//
1534		s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
1535		s -= fa->texturemins[0];
1536		s += fa->light_s*16;
1537		s += 8;
1538		s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
1539
1540		t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
1541		t -= fa->texturemins[1];
1542		t += fa->light_t*16;
1543		t += 8;
1544		t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
1545
1546		poly->verts[i][5] = s;
1547		poly->verts[i][6] = t;
1548	}
1549
1550	//
1551	// remove co-linear points - Ed
1552	//
1553	if (!gl_keeptjunctions.value && !(fa->flags & SURF_UNDERWATER) )
1554	{
1555		for (i = 0 ; i < lnumverts ; ++i)
1556		{
1557			vec3_t v1, v2;
1558			float *prev, *this, *next;
1559
1560			prev = poly->verts[(i + lnumverts - 1) % lnumverts];
1561			this = poly->verts[i];
1562			next = poly->verts[(i + 1) % lnumverts];
1563
1564			VectorSubtract( this, prev, v1 );
1565			VectorNormalize( v1 );
1566			VectorSubtract( next, prev, v2 );
1567			VectorNormalize( v2 );
1568
1569			// skip co-linear points
1570			#define COLINEAR_EPSILON 0.001
1571			if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
1572				(fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) &&
1573				(fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
1574			{
1575				int j;
1576				for (j = i + 1; j < lnumverts; ++j)
1577				{
1578					int k;
1579					for (k = 0; k < VERTEXSIZE; ++k)
1580						poly->verts[j - 1][k] = poly->verts[j][k];
1581				}
1582				--lnumverts;
1583				++nColinElim;
1584				// retry next vertex next time, which is now current vertex
1585				--i;
1586			}
1587		}
1588	}
1589	poly->numverts = lnumverts;
1590
1591}
1592
1593/*
1594========================
1595GL_CreateSurfaceLightmap
1596========================
1597*/
1598void GL_CreateSurfaceLightmap (msurface_t *surf)
1599{
1600	int		smax, tmax;
1601	byte	*base;
1602
1603	if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
1604		return;
1605
1606	smax = (surf->extents[0]>>4)+1;
1607	tmax = (surf->extents[1]>>4)+1;
1608
1609	surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
1610	base = lightmaps + surf->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
1611	base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
1612	R_BuildLightMap (surf, base, BLOCK_WIDTH*lightmap_bytes);
1613}
1614
1615
1616/*
1617==================
1618GL_BuildLightmaps
1619
1620Builds the lightmap texture
1621with all the surfaces from all brush models
1622==================
1623*/
1624void GL_BuildLightmaps (void)
1625{
1626	int		i, j;
1627	model_t	*m;
1628
1629	memset (allocated, 0, sizeof(allocated));
1630
1631	r_framecount = 1;		// no dlightcache
1632
1633	if (!lightmap_textures)
1634	{
1635		lightmap_textures = texture_extension_number;
1636		texture_extension_number += MAX_LIGHTMAPS;
1637	}
1638
1639	gl_lightmap_format = GL_LUMINANCE;
1640	if (COM_CheckParm ("-lm_1"))
1641		gl_lightmap_format = GL_LUMINANCE;
1642	if (COM_CheckParm ("-lm_a"))
1643		gl_lightmap_format = GL_ALPHA;
1644	if (COM_CheckParm ("-lm_i"))
1645		gl_lightmap_format = GL_INTENSITY;
1646	if (COM_CheckParm ("-lm_2"))
1647		gl_lightmap_format = GL_RGBA4;
1648	if (COM_CheckParm ("-lm_4"))
1649		gl_lightmap_format = GL_RGBA;
1650
1651	switch (gl_lightmap_format)
1652	{
1653	case GL_RGBA:
1654		lightmap_bytes = 4;
1655		break;
1656	case GL_RGBA4:
1657		lightmap_bytes = 2;
1658		break;
1659	case GL_LUMINANCE:
1660	case GL_INTENSITY:
1661	case GL_ALPHA:
1662		lightmap_bytes = 1;
1663		break;
1664	}
1665
1666	for (j=1 ; j<MAX_MODELS ; j++)
1667	{
1668		m = cl.model_precache[j];
1669		if (!m)
1670			break;
1671		if (m->name[0] == '*')
1672			continue;
1673		r_pcurrentvertbase = m->vertexes;
1674		currentmodel = m;
1675		for (i=0 ; i<m->numsurfaces ; i++)
1676		{
1677			GL_CreateSurfaceLightmap (m->surfaces + i);
1678			if ( m->surfaces[i].flags & SURF_DRAWTURB )
1679				continue;
1680#ifndef QUAKE2
1681			if ( m->surfaces[i].flags & SURF_DRAWSKY )
1682				continue;
1683#endif
1684			BuildSurfaceDisplayList (m->surfaces + i);
1685		}
1686	}
1687
1688 	if (!gl_texsort.value)
1689 		GL_SelectTexture(TEXTURE1_SGIS);
1690
1691	//
1692	// upload all lightmaps that were filled
1693	//
1694	for (i=0 ; i<MAX_LIGHTMAPS ; i++)
1695	{
1696		if (!allocated[i][0])
1697			break;		// no more used
1698		lightmap_modified[i] = false;
1699		lightmap_rectchange[i].l = BLOCK_WIDTH;
1700		lightmap_rectchange[i].t = BLOCK_HEIGHT;
1701		lightmap_rectchange[i].w = 0;
1702		lightmap_rectchange[i].h = 0;
1703		GL_Bind(lightmap_textures + i);
1704		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1705		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1706		glTexImage2DHelper (GL_TEXTURE_2D, 0, lightmap_bytes
1707		, BLOCK_WIDTH, BLOCK_HEIGHT, 0,
1708		gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
1709	}
1710
1711 	if (!gl_texsort.value)
1712 		GL_SelectTexture(TEXTURE0_SGIS);
1713
1714}
1715
1716