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