1 /*
2 Copyright (C) 2003-2006 Andrey Nazarov
3 Copyright (C) 1997-2001 Id Software, Inc.
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14 See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 
20 */
21 
22 #include "gl_local.h"
23 
24 static char	skyname[MAX_QPATH];
25 static float	skyrotate;
26 static vec3_t	skyaxis;
27 static image_t	*sky_images[6];
28 
29 static vec3_t	skyclip[6] = {
30 	{1,1,0},
31 	{1,-1,0},
32 	{0,-1,1},
33 	{0,1,1},
34 	{1,0,1},
35 	{-1,0,1}
36 };
37 
38 // 1 = s, 2 = t, 3 = 2048
39 static int	st_to_vec[6][3] = {
40 	{3,-1,2},
41 	{-3,1,2},
42 
43 	{1,3,2},
44 	{-1,-3,2},
45 
46 	{-2,-1,3},		// 0 degrees yaw, look straight up
47 	{2,-1,-3}		// look straight down
48 };
49 
50 // s = [0]/[2], t = [1]/[2]
51 static int	vec_to_st[6][3] = {
52 	{-2,3,1},
53 	{2,3,-1},
54 
55 	{1,3,2},
56 	{-1,3,-2},
57 
58 	{-2,-1,3},
59 	{-2,1,-3}
60 };
61 
62 static float	skymins[2][6], skymaxs[2][6];
63 static float	sky_min, sky_max;
64 
DrawSkyPolygon(int nump,vec3_t vecs)65 static void DrawSkyPolygon (int nump, vec3_t vecs)
66 {
67 	int		i,j;
68 	vec3_t	v, av;
69 	float	s, t, dv;
70 	int		axis;
71 	float	*vp;
72 
73 	// decide which face it maps to
74 	VectorCopy (vec3_origin, v);
75 	for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
76 	{
77 		VectorAdd (vp, v, v);
78 	}
79 	av[0] = fabs(v[0]);
80 	av[1] = fabs(v[1]);
81 	av[2] = fabs(v[2]);
82 	if (av[0] > av[1] && av[0] > av[2])
83 	{
84 		if (v[0] < 0)
85 			axis = 1;
86 		else
87 			axis = 0;
88 	}
89 	else if (av[1] > av[2] && av[1] > av[0])
90 	{
91 		if (v[1] < 0)
92 			axis = 3;
93 		else
94 			axis = 2;
95 	}
96 	else
97 	{
98 		if (v[2] < 0)
99 			axis = 5;
100 		else
101 			axis = 4;
102 	}
103 
104 	// project new texture coords
105 	for (i=0 ; i<nump ; i++, vecs+=3)
106 	{
107 		j = vec_to_st[axis][2];
108 		if (j > 0)
109 			dv = vecs[j - 1];
110 		else
111 			dv = -vecs[-j - 1];
112 		if (dv < 0.001)
113 			continue;	// don't divide by zero
114 		j = vec_to_st[axis][0];
115 		if (j < 0)
116 			s = -vecs[-j -1] / dv;
117 		else
118 			s = vecs[j-1] / dv;
119 		j = vec_to_st[axis][1];
120 		if (j < 0)
121 			t = -vecs[-j -1] / dv;
122 		else
123 			t = vecs[j-1] / dv;
124 
125 		if (s < skymins[0][axis])
126 			skymins[0][axis] = s;
127 		if (t < skymins[1][axis])
128 			skymins[1][axis] = t;
129 		if (s > skymaxs[0][axis])
130 			skymaxs[0][axis] = s;
131 		if (t > skymaxs[1][axis])
132 			skymaxs[1][axis] = t;
133 	}
134 }
135 
136 #define	ON_EPSILON		0.1			// point on plane side epsilon
137 #define	MAX_CLIP_VERTS	64
138 
139 #define	SIDE_FRONT	0
140 #define	SIDE_BACK	1
141 #define	SIDE_ON		2
142 
ClipSkyPolygon(int nump,vec3_t vecs,int stage)143 static void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
144 {
145 	float	*norm;
146 	float	*v;
147 	qboolean	front, back;
148 	float	d, e;
149 	float	dists[MAX_CLIP_VERTS];
150 	int		sides[MAX_CLIP_VERTS];
151 	vec3_t	newv[2][MAX_CLIP_VERTS];
152 	int		newc[2];
153 	int		i, j;
154 
155 	if (nump > MAX_CLIP_VERTS-2)
156 		Com_Error( ERR_DROP,  "ClipSkyPolygon: MAX_CLIP_VERTS");
157 	if (stage == 6)
158 	{	// fully clipped, so draw it
159 		DrawSkyPolygon (nump, vecs);
160 		return;
161 	}
162 
163 	front = back = qfalse;
164 	norm = skyclip[stage];
165 	for (i=0, v = vecs ; i<nump ; i++, v+=3)
166 	{
167 		d = DotProduct (v, norm);
168 		if (d > ON_EPSILON)
169 		{
170 			front = qtrue;
171 			sides[i] = SIDE_FRONT;
172 		}
173 		else if (d < -ON_EPSILON)
174 		{
175 			back = qtrue;
176 			sides[i] = SIDE_BACK;
177 		}
178 		else
179 			sides[i] = SIDE_ON;
180 		dists[i] = d;
181 	}
182 
183 	if (!front || !back)
184 	{	// not clipped
185 		ClipSkyPolygon (nump, vecs, stage+1);
186 		return;
187 	}
188 
189 	// clip it
190 	sides[i] = sides[0];
191 	dists[i] = dists[0];
192 	VectorCopy (vecs, (vecs+(i*3)) );
193 	newc[0] = newc[1] = 0;
194 
195 	for (i=0, v = vecs ; i<nump ; i++, v+=3)
196 	{
197 		switch (sides[i])
198 		{
199 		case SIDE_FRONT:
200 			VectorCopy (v, newv[0][newc[0]]);
201 			newc[0]++;
202 			break;
203 		case SIDE_BACK:
204 			VectorCopy (v, newv[1][newc[1]]);
205 			newc[1]++;
206 			break;
207 		case SIDE_ON:
208 			VectorCopy (v, newv[0][newc[0]]);
209 			newc[0]++;
210 			VectorCopy (v, newv[1][newc[1]]);
211 			newc[1]++;
212 			break;
213 		}
214 
215 		if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
216 			continue;
217 
218 		d = dists[i] / (dists[i] - dists[i+1]);
219 		for (j=0 ; j<3 ; j++)
220 		{
221 			e = v[j] + d*(v[j+3] - v[j]);
222 			newv[0][newc[0]][j] = e;
223 			newv[1][newc[1]][j] = e;
224 		}
225 		newc[0]++;
226 		newc[1]++;
227 	}
228 
229 	// continue
230 	ClipSkyPolygon (newc[0], newv[0][0], stage+1);
231 	ClipSkyPolygon (newc[1], newv[1][0], stage+1);
232 }
233 
234 /*
235 =================
236 R_AddSkySurface
237 =================
238 */
R_AddSkySurface(bspSurface_t * fa)239 void R_AddSkySurface( bspSurface_t *fa ) {
240 	int			i;
241 	vec3_t		verts[MAX_CLIP_VERTS];
242 	bspPoly_t	*p;
243     vec_t *vert;
244 
245 	// calculate vertex values for sky box
246 	for (p=fa->polys ; p ; p=p->next)
247 	{
248         vert = p->vertices;
249 		for (i=0 ; i<p->numVerts ; i++)
250 		{
251 			VectorSubtract (vert, modelViewOrigin, verts[i]);
252             vert += VERTEX_SIZE;
253 		}
254 		ClipSkyPolygon (p->numVerts, verts[0], 0);
255 	}
256 }
257 
258 
259 /*
260 ==============
261 R_ClearSkyBox
262 ==============
263 */
R_ClearSkyBox(void)264 void R_ClearSkyBox( void ) {
265 	int		i;
266 
267 	for (i=0 ; i<6 ; i++)
268 	{
269 		skymins[0][i] = skymins[1][i] = 9999;
270 		skymaxs[0][i] = skymaxs[1][i] = -9999;
271 	}
272 }
273 
274 
MakeSkyVec(float s,float t,int axis)275 static void MakeSkyVec (float s, float t, int axis)
276 {
277 	vec3_t		v, b;
278 	int			j, k;
279 
280 	b[0] = s*4800;//2300;
281 	b[1] = t*4800;//2300;
282 	b[2] = 4800;//2300;
283 
284 	for (j=0 ; j<3 ; j++)
285 	{
286 		k = st_to_vec[axis][j];
287 		if (k < 0)
288 			v[j] = -b[-k - 1];
289 		else
290 			v[j] = b[k - 1];
291 	}
292 
293 	// avoid bilerp seam
294 	s = (s+1)*0.5;
295 	t = (t+1)*0.5;
296 
297 	if (s < sky_min)
298 		s = sky_min;
299 	else if (s > sky_max)
300 		s = sky_max;
301 	if (t < sky_min)
302 		t = sky_min;
303 	else if (t > sky_max)
304 		t = sky_max;
305 
306 	t = 1.0 - t;
307 	qglTexCoord2f (s, t);
308 	qglVertex3fv (v);
309 }
310 
311 
312 /*
313 ==============
314 R_DrawSkyBox
315 ==============
316 */
R_DrawSkyBox(void)317 void R_DrawSkyBox( void ) {
318 	int		i;
319     static int	skytexorder[6] = {0,2,1,3,4,5};
320 
321 	if (skyrotate)
322 	{	// check for no sky at all
323 		for (i=0 ; i<6 ; i++)
324 			if (skymins[0][i] < skymaxs[0][i]
325 			&& skymins[1][i] < skymaxs[1][i])
326 				break;
327 		if (i == 6)
328 			return;		// nothing visible
329 	}
330 
331 	qglPushMatrix ();
332 	qglTranslatef (modelViewOrigin[0], modelViewOrigin[1], modelViewOrigin[2]);
333 	qglRotatef (glr.fd.time * skyrotate,
334             skyaxis[0], skyaxis[1], skyaxis[2]);
335 	qglColor3f( 1, 1, 1 );
336 	GL_Bits( GLS_DEFAULT );
337 
338 	for (i=0 ; i<6 ; i++)
339 	{
340 		if (skyrotate)
341 		{	// hack, forces full sky to draw when rotating
342 			skymins[0][i] = -1;
343 			skymins[1][i] = -1;
344 			skymaxs[0][i] = 1;
345 			skymaxs[1][i] = 1;
346 		}
347 
348 		if (skymins[0][i] >= skymaxs[0][i]
349 		|| skymins[1][i] >= skymaxs[1][i])
350 			continue;
351 
352 		GL_BindTexture (sky_images[skytexorder[i]]->texnum);
353 
354 		qglBegin (GL_QUADS);
355 		MakeSkyVec (skymins[0][i], skymins[1][i], i);
356 		MakeSkyVec (skymins[0][i], skymaxs[1][i], i);
357 		MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i);
358 		MakeSkyVec (skymaxs[0][i], skymins[1][i], i);
359 		qglEnd ();
360 	}
361 	qglPopMatrix ();
362 }
363 
364 
365 /*
366 ============
367 R_SetSky
368 ============
369 */
R_SetSky(const char * name,float rotate,vec3_t axis)370 void R_SetSky( const char *name, float rotate, vec3_t axis ) {
371 	int		i;
372 	char	pathname[MAX_QPATH];
373     // 3dstudio environment map names
374     static char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
375 
376 	Q_strncpyz( skyname, name, sizeof( skyname ) );
377 	skyrotate = rotate;
378 	VectorCopy (axis, skyaxis);
379 
380 	for (i=0 ; i<6 ; i++)
381 	{
382 		Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga",
383                 skyname, suf[i]);
384 
385 		sky_images[i] = R_FindImage (pathname, it_sky);
386 		if (!sky_images[i])
387 			sky_images[i] = r_notexture;
388 
389 		/*if (gl_skymip->integer || skyrotate)
390 		{	// take less memory
391 			sky_min = 1.0/256;
392 			sky_max = 255.0/256;
393 		}
394 		else*/
395 		{
396 			sky_min = 1.0/512;
397 			sky_max = 511.0/512;
398 		}
399 	}
400 
401 }
402 
403