Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

gl_warp.c (12452B)


      1 /*
      2 Copyright (C) 1997-2001 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 // gl_warp.c -- sky and water polygons
     21 
     22 #include "gl_local.h"
     23 
     24 extern	model_t	*loadmodel;
     25 
     26 char	skyname[MAX_QPATH];
     27 float	skyrotate;
     28 vec3_t	skyaxis;
     29 image_t	*sky_images[6];
     30 
     31 msurface_t	*warpface;
     32 
     33 #define	SUBDIVIDE_SIZE	64
     34 //#define	SUBDIVIDE_SIZE	1024
     35 
     36 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
     37 {
     38 	int		i, j;
     39 	float	*v;
     40 
     41 	mins[0] = mins[1] = mins[2] = 9999;
     42 	maxs[0] = maxs[1] = maxs[2] = -9999;
     43 	v = verts;
     44 	for (i=0 ; i<numverts ; i++)
     45 		for (j=0 ; j<3 ; j++, v++)
     46 		{
     47 			if (*v < mins[j])
     48 				mins[j] = *v;
     49 			if (*v > maxs[j])
     50 				maxs[j] = *v;
     51 		}
     52 }
     53 
     54 void SubdividePolygon (int numverts, float *verts)
     55 {
     56 	int		i, j, k;
     57 	vec3_t	mins, maxs;
     58 	float	m;
     59 	float	*v;
     60 	vec3_t	front[64], back[64];
     61 	int		f, b;
     62 	float	dist[64];
     63 	float	frac;
     64 	glpoly_t	*poly;
     65 	float	s, t;
     66 	vec3_t	total;
     67 	float	total_s, total_t;
     68 
     69 	if (numverts > 60)
     70 		ri.Sys_Error (ERR_DROP, "numverts = %i", numverts);
     71 
     72 	BoundPoly (numverts, verts, mins, maxs);
     73 
     74 	for (i=0 ; i<3 ; i++)
     75 	{
     76 		m = (mins[i] + maxs[i]) * 0.5;
     77 		m = SUBDIVIDE_SIZE * floor (m/SUBDIVIDE_SIZE + 0.5);
     78 		if (maxs[i] - m < 8)
     79 			continue;
     80 		if (m - mins[i] < 8)
     81 			continue;
     82 
     83 		// cut it
     84 		v = verts + i;
     85 		for (j=0 ; j<numverts ; j++, v+= 3)
     86 			dist[j] = *v - m;
     87 
     88 		// wrap cases
     89 		dist[j] = dist[0];
     90 		v-=i;
     91 		VectorCopy (verts, v);
     92 
     93 		f = b = 0;
     94 		v = verts;
     95 		for (j=0 ; j<numverts ; j++, v+= 3)
     96 		{
     97 			if (dist[j] >= 0)
     98 			{
     99 				VectorCopy (v, front[f]);
    100 				f++;
    101 			}
    102 			if (dist[j] <= 0)
    103 			{
    104 				VectorCopy (v, back[b]);
    105 				b++;
    106 			}
    107 			if (dist[j] == 0 || dist[j+1] == 0)
    108 				continue;
    109 			if ( (dist[j] > 0) != (dist[j+1] > 0) )
    110 			{
    111 				// clip point
    112 				frac = dist[j] / (dist[j] - dist[j+1]);
    113 				for (k=0 ; k<3 ; k++)
    114 					front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]);
    115 				f++;
    116 				b++;
    117 			}
    118 		}
    119 
    120 		SubdividePolygon (f, front[0]);
    121 		SubdividePolygon (b, back[0]);
    122 		return;
    123 	}
    124 
    125 	// add a point in the center to help keep warp valid
    126 	poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * VERTEXSIZE*sizeof(float));
    127 	poly->next = warpface->polys;
    128 	warpface->polys = poly;
    129 	poly->numverts = numverts+2;
    130 	VectorClear (total);
    131 	total_s = 0;
    132 	total_t = 0;
    133 	for (i=0 ; i<numverts ; i++, verts+= 3)
    134 	{
    135 		VectorCopy (verts, poly->verts[i+1]);
    136 		s = DotProduct (verts, warpface->texinfo->vecs[0]);
    137 		t = DotProduct (verts, warpface->texinfo->vecs[1]);
    138 
    139 		total_s += s;
    140 		total_t += t;
    141 		VectorAdd (total, verts, total);
    142 
    143 		poly->verts[i+1][3] = s;
    144 		poly->verts[i+1][4] = t;
    145 	}
    146 
    147 	VectorScale (total, (1.0/numverts), poly->verts[0]);
    148 	poly->verts[0][3] = total_s/numverts;
    149 	poly->verts[0][4] = total_t/numverts;
    150 
    151 	// copy first vertex to last
    152 	memcpy (poly->verts[i+1], poly->verts[1], sizeof(poly->verts[0]));
    153 }
    154 
    155 /*
    156 ================
    157 GL_SubdivideSurface
    158 
    159 Breaks a polygon up along axial 64 unit
    160 boundaries so that turbulent and sky warps
    161 can be done reasonably.
    162 ================
    163 */
    164 void GL_SubdivideSurface (msurface_t *fa)
    165 {
    166 	vec3_t		verts[64];
    167 	int			numverts;
    168 	int			i;
    169 	int			lindex;
    170 	float		*vec;
    171 
    172 	warpface = fa;
    173 
    174 	//
    175 	// convert edges back to a normal polygon
    176 	//
    177 	numverts = 0;
    178 	for (i=0 ; i<fa->numedges ; i++)
    179 	{
    180 		lindex = loadmodel->surfedges[fa->firstedge + i];
    181 
    182 		if (lindex > 0)
    183 			vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
    184 		else
    185 			vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
    186 		VectorCopy (vec, verts[numverts]);
    187 		numverts++;
    188 	}
    189 
    190 	SubdividePolygon (numverts, verts[0]);
    191 }
    192 
    193 //=========================================================
    194 
    195 
    196 
    197 // speed up sin calculations - Ed
    198 float	r_turbsin[] =
    199 {
    200 	#include "warpsin.h"
    201 };
    202 #define TURBSCALE (256.0 / (2 * M_PI))
    203 
    204 /*
    205 =============
    206 EmitWaterPolys
    207 
    208 Does a water warp on the pre-fragmented glpoly_t chain
    209 =============
    210 */
    211 void EmitWaterPolys (msurface_t *fa)
    212 {
    213 	glpoly_t	*p, *bp;
    214 	float		*v;
    215 	int			i;
    216 	float		s, t, os, ot;
    217 	float		scroll;
    218 	float		rdt = r_newrefdef.time;
    219 
    220 	if (fa->texinfo->flags & SURF_FLOWING)
    221 		scroll = -64 * ( (r_newrefdef.time*0.5) - (int)(r_newrefdef.time*0.5) );
    222 	else
    223 		scroll = 0;
    224 	for (bp=fa->polys ; bp ; bp=bp->next)
    225 	{
    226 		p = bp;
    227 
    228 		qglBegin (GL_TRIANGLE_FAN);
    229 		for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)
    230 		{
    231 			os = v[3];
    232 			ot = v[4];
    233 
    234 #if !id386
    235 			s = os + r_turbsin[(int)((ot*0.125+r_newrefdef.time) * TURBSCALE) & 255];
    236 #else
    237 			s = os + r_turbsin[Q_ftol( ((ot*0.125+rdt) * TURBSCALE) ) & 255];
    238 #endif
    239 			s += scroll;
    240 			s *= (1.0/64);
    241 
    242 #if !id386
    243 			t = ot + r_turbsin[(int)((os*0.125+rdt) * TURBSCALE) & 255];
    244 #else
    245 			t = ot + r_turbsin[Q_ftol( ((os*0.125+rdt) * TURBSCALE) ) & 255];
    246 #endif
    247 			t *= (1.0/64);
    248 
    249 			qglTexCoord2f (s, t);
    250 			qglVertex3fv (v);
    251 		}
    252 		qglEnd ();
    253 	}
    254 }
    255 
    256 
    257 //===================================================================
    258 
    259 
    260 vec3_t	skyclip[6] = {
    261 	{1,1,0},
    262 	{1,-1,0},
    263 	{0,-1,1},
    264 	{0,1,1},
    265 	{1,0,1},
    266 	{-1,0,1} 
    267 };
    268 int	c_sky;
    269 
    270 // 1 = s, 2 = t, 3 = 2048
    271 int	st_to_vec[6][3] =
    272 {
    273 	{3,-1,2},
    274 	{-3,1,2},
    275 
    276 	{1,3,2},
    277 	{-1,-3,2},
    278 
    279 	{-2,-1,3},		// 0 degrees yaw, look straight up
    280 	{2,-1,-3}		// look straight down
    281 
    282 //	{-1,2,3},
    283 //	{1,2,-3}
    284 };
    285 
    286 // s = [0]/[2], t = [1]/[2]
    287 int	vec_to_st[6][3] =
    288 {
    289 	{-2,3,1},
    290 	{2,3,-1},
    291 
    292 	{1,3,2},
    293 	{-1,3,-2},
    294 
    295 	{-2,-1,3},
    296 	{-2,1,-3}
    297 
    298 //	{-1,2,3},
    299 //	{1,2,-3}
    300 };
    301 
    302 float	skymins[2][6], skymaxs[2][6];
    303 float	sky_min, sky_max;
    304 
    305 void DrawSkyPolygon (int nump, vec3_t vecs)
    306 {
    307 	int		i,j;
    308 	vec3_t	v, av;
    309 	float	s, t, dv;
    310 	int		axis;
    311 	float	*vp;
    312 
    313 	c_sky++;
    314 #if 0
    315 glBegin (GL_POLYGON);
    316 for (i=0 ; i<nump ; i++, vecs+=3)
    317 {
    318 	VectorAdd(vecs, r_origin, v);
    319 	qglVertex3fv (v);
    320 }
    321 glEnd();
    322 return;
    323 #endif
    324 	// decide which face it maps to
    325 	VectorCopy (vec3_origin, v);
    326 	for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
    327 	{
    328 		VectorAdd (vp, v, v);
    329 	}
    330 	av[0] = fabs(v[0]);
    331 	av[1] = fabs(v[1]);
    332 	av[2] = fabs(v[2]);
    333 	if (av[0] > av[1] && av[0] > av[2])
    334 	{
    335 		if (v[0] < 0)
    336 			axis = 1;
    337 		else
    338 			axis = 0;
    339 	}
    340 	else if (av[1] > av[2] && av[1] > av[0])
    341 	{
    342 		if (v[1] < 0)
    343 			axis = 3;
    344 		else
    345 			axis = 2;
    346 	}
    347 	else
    348 	{
    349 		if (v[2] < 0)
    350 			axis = 5;
    351 		else
    352 			axis = 4;
    353 	}
    354 
    355 	// project new texture coords
    356 	for (i=0 ; i<nump ; i++, vecs+=3)
    357 	{
    358 		j = vec_to_st[axis][2];
    359 		if (j > 0)
    360 			dv = vecs[j - 1];
    361 		else
    362 			dv = -vecs[-j - 1];
    363 		if (dv < 0.001)
    364 			continue;	// don't divide by zero
    365 		j = vec_to_st[axis][0];
    366 		if (j < 0)
    367 			s = -vecs[-j -1] / dv;
    368 		else
    369 			s = vecs[j-1] / dv;
    370 		j = vec_to_st[axis][1];
    371 		if (j < 0)
    372 			t = -vecs[-j -1] / dv;
    373 		else
    374 			t = vecs[j-1] / dv;
    375 
    376 		if (s < skymins[0][axis])
    377 			skymins[0][axis] = s;
    378 		if (t < skymins[1][axis])
    379 			skymins[1][axis] = t;
    380 		if (s > skymaxs[0][axis])
    381 			skymaxs[0][axis] = s;
    382 		if (t > skymaxs[1][axis])
    383 			skymaxs[1][axis] = t;
    384 	}
    385 }
    386 
    387 #define	ON_EPSILON		0.1			// point on plane side epsilon
    388 #define	MAX_CLIP_VERTS	64
    389 void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
    390 {
    391 	float	*norm;
    392 	float	*v;
    393 	qboolean	front, back;
    394 	float	d, e;
    395 	float	dists[MAX_CLIP_VERTS];
    396 	int		sides[MAX_CLIP_VERTS];
    397 	vec3_t	newv[2][MAX_CLIP_VERTS];
    398 	int		newc[2];
    399 	int		i, j;
    400 
    401 	if (nump > MAX_CLIP_VERTS-2)
    402 		ri.Sys_Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
    403 	if (stage == 6)
    404 	{	// fully clipped, so draw it
    405 		DrawSkyPolygon (nump, vecs);
    406 		return;
    407 	}
    408 
    409 	front = back = false;
    410 	norm = skyclip[stage];
    411 	for (i=0, v = vecs ; i<nump ; i++, v+=3)
    412 	{
    413 		d = DotProduct (v, norm);
    414 		if (d > ON_EPSILON)
    415 		{
    416 			front = true;
    417 			sides[i] = SIDE_FRONT;
    418 		}
    419 		else if (d < -ON_EPSILON)
    420 		{
    421 			back = true;
    422 			sides[i] = SIDE_BACK;
    423 		}
    424 		else
    425 			sides[i] = SIDE_ON;
    426 		dists[i] = d;
    427 	}
    428 
    429 	if (!front || !back)
    430 	{	// not clipped
    431 		ClipSkyPolygon (nump, vecs, stage+1);
    432 		return;
    433 	}
    434 
    435 	// clip it
    436 	sides[i] = sides[0];
    437 	dists[i] = dists[0];
    438 	VectorCopy (vecs, (vecs+(i*3)) );
    439 	newc[0] = newc[1] = 0;
    440 
    441 	for (i=0, v = vecs ; i<nump ; i++, v+=3)
    442 	{
    443 		switch (sides[i])
    444 		{
    445 		case SIDE_FRONT:
    446 			VectorCopy (v, newv[0][newc[0]]);
    447 			newc[0]++;
    448 			break;
    449 		case SIDE_BACK:
    450 			VectorCopy (v, newv[1][newc[1]]);
    451 			newc[1]++;
    452 			break;
    453 		case SIDE_ON:
    454 			VectorCopy (v, newv[0][newc[0]]);
    455 			newc[0]++;
    456 			VectorCopy (v, newv[1][newc[1]]);
    457 			newc[1]++;
    458 			break;
    459 		}
    460 
    461 		if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
    462 			continue;
    463 
    464 		d = dists[i] / (dists[i] - dists[i+1]);
    465 		for (j=0 ; j<3 ; j++)
    466 		{
    467 			e = v[j] + d*(v[j+3] - v[j]);
    468 			newv[0][newc[0]][j] = e;
    469 			newv[1][newc[1]][j] = e;
    470 		}
    471 		newc[0]++;
    472 		newc[1]++;
    473 	}
    474 
    475 	// continue
    476 	ClipSkyPolygon (newc[0], newv[0][0], stage+1);
    477 	ClipSkyPolygon (newc[1], newv[1][0], stage+1);
    478 }
    479 
    480 /*
    481 =================
    482 R_AddSkySurface
    483 =================
    484 */
    485 void R_AddSkySurface (msurface_t *fa)
    486 {
    487 	int			i;
    488 	vec3_t		verts[MAX_CLIP_VERTS];
    489 	glpoly_t	*p;
    490 
    491 	// calculate vertex values for sky box
    492 	for (p=fa->polys ; p ; p=p->next)
    493 	{
    494 		for (i=0 ; i<p->numverts ; i++)
    495 		{
    496 			VectorSubtract (p->verts[i], r_origin, verts[i]);
    497 		}
    498 		ClipSkyPolygon (p->numverts, verts[0], 0);
    499 	}
    500 }
    501 
    502 
    503 /*
    504 ==============
    505 R_ClearSkyBox
    506 ==============
    507 */
    508 void R_ClearSkyBox (void)
    509 {
    510 	int		i;
    511 
    512 	for (i=0 ; i<6 ; i++)
    513 	{
    514 		skymins[0][i] = skymins[1][i] = 9999;
    515 		skymaxs[0][i] = skymaxs[1][i] = -9999;
    516 	}
    517 }
    518 
    519 
    520 void MakeSkyVec (float s, float t, int axis)
    521 {
    522 	vec3_t		v, b;
    523 	int			j, k;
    524 
    525 	b[0] = s*2300;
    526 	b[1] = t*2300;
    527 	b[2] = 2300;
    528 
    529 	for (j=0 ; j<3 ; j++)
    530 	{
    531 		k = st_to_vec[axis][j];
    532 		if (k < 0)
    533 			v[j] = -b[-k - 1];
    534 		else
    535 			v[j] = b[k - 1];
    536 	}
    537 
    538 	// avoid bilerp seam
    539 	s = (s+1)*0.5;
    540 	t = (t+1)*0.5;
    541 
    542 	if (s < sky_min)
    543 		s = sky_min;
    544 	else if (s > sky_max)
    545 		s = sky_max;
    546 	if (t < sky_min)
    547 		t = sky_min;
    548 	else if (t > sky_max)
    549 		t = sky_max;
    550 
    551 	t = 1.0 - t;
    552 	qglTexCoord2f (s, t);
    553 	qglVertex3fv (v);
    554 }
    555 
    556 /*
    557 ==============
    558 R_DrawSkyBox
    559 ==============
    560 */
    561 int	skytexorder[6] = {0,2,1,3,4,5};
    562 void R_DrawSkyBox (void)
    563 {
    564 	int		i;
    565 
    566 #if 0
    567 qglEnable (GL_BLEND);
    568 GL_TexEnv( GL_MODULATE );
    569 qglColor4f (1,1,1,0.5);
    570 qglDisable (GL_DEPTH_TEST);
    571 #endif
    572 	if (skyrotate)
    573 	{	// check for no sky at all
    574 		for (i=0 ; i<6 ; i++)
    575 			if (skymins[0][i] < skymaxs[0][i]
    576 			&& skymins[1][i] < skymaxs[1][i])
    577 				break;
    578 		if (i == 6)
    579 			return;		// nothing visible
    580 	}
    581 
    582 qglPushMatrix ();
    583 qglTranslatef (r_origin[0], r_origin[1], r_origin[2]);
    584 qglRotatef (r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]);
    585 
    586 	for (i=0 ; i<6 ; i++)
    587 	{
    588 		if (skyrotate)
    589 		{	// hack, forces full sky to draw when rotating
    590 			skymins[0][i] = -1;
    591 			skymins[1][i] = -1;
    592 			skymaxs[0][i] = 1;
    593 			skymaxs[1][i] = 1;
    594 		}
    595 
    596 		if (skymins[0][i] >= skymaxs[0][i]
    597 		|| skymins[1][i] >= skymaxs[1][i])
    598 			continue;
    599 
    600 		GL_Bind (sky_images[skytexorder[i]]->texnum);
    601 
    602 		qglBegin (GL_QUADS);
    603 		MakeSkyVec (skymins[0][i], skymins[1][i], i);
    604 		MakeSkyVec (skymins[0][i], skymaxs[1][i], i);
    605 		MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i);
    606 		MakeSkyVec (skymaxs[0][i], skymins[1][i], i);
    607 		qglEnd ();
    608 	}
    609 qglPopMatrix ();
    610 #if 0
    611 glDisable (GL_BLEND);
    612 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    613 glColor4f (1,1,1,0.5);
    614 glEnable (GL_DEPTH_TEST);
    615 #endif
    616 }
    617 
    618 
    619 /*
    620 ============
    621 R_SetSky
    622 ============
    623 */
    624 // 3dstudio environment map names
    625 char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
    626 void R_SetSky (char *name, float rotate, vec3_t axis)
    627 {
    628 	int		i;
    629 	char	pathname[MAX_QPATH];
    630 
    631 	strncpy (skyname, name, sizeof(skyname)-1);
    632 	skyrotate = rotate;
    633 	VectorCopy (axis, skyaxis);
    634 
    635 	for (i=0 ; i<6 ; i++)
    636 	{
    637 		// chop down rotating skies for less memory
    638 		if (gl_skymip->value || skyrotate)
    639 			gl_picmip->value++;
    640 
    641 		if ( qglColorTableEXT && gl_ext_palettedtexture->value )
    642 			Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[i]);
    643 		else
    644 			Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga", skyname, suf[i]);
    645 
    646 		sky_images[i] = GL_FindImage (pathname, it_sky);
    647 		if (!sky_images[i])
    648 			sky_images[i] = r_notexture;
    649 
    650 		if (gl_skymip->value || skyrotate)
    651 		{	// take less memory
    652 			gl_picmip->value--;
    653 			sky_min = 1.0/256;
    654 			sky_max = 255.0/256;
    655 		}
    656 		else	
    657 		{
    658 			sky_min = 1.0/512;
    659 			sky_max = 511.0/512;
    660 		}
    661 	}
    662 }