two-layer sky rendering now uses GL_ARB_texture_env_combine if available to render...
[divverent/darkplaces.git] / gl_poly.c
1 #include "quakedef.h"
2
3 transvert_t *transvert;
4 transpoly_t *transpoly;
5 unsigned short *transpolyindex;
6 wallvert_t *wallvert;
7 wallvertcolor_t *wallvertcolor;
8 wallpoly_t *wallpoly;
9 skyvert_t *skyvert;
10 skypoly_t *skypoly;
11
12 int currenttranspoly;
13 int currenttransvert;
14 int currentwallpoly;
15 int currentwallvert;
16 int currentskypoly;
17 int currentskyvert;
18
19 void LoadSky_f(void);
20
21 cvar_t r_multitexture = {0, "r_multitexture", "1"};
22 cvar_t r_skyquality = {CVAR_SAVE, "r_skyquality", "2"};
23 cvar_t r_mergesky = {CVAR_SAVE, "r_mergesky", "0"};
24
25 static char skyworldname[1024];
26 static rtexture_t *mergeskytexture;
27 static rtexture_t *solidskytexture, *solidskytexture_half;
28 static rtexture_t *alphaskytexture, *alphaskytexture_half;
29 static qboolean skyavailable_quake;
30 static qboolean skyavailable_box;
31
32 void R_BuildSky (int scrollupper, int scrolllower);
33
34 typedef struct translistitem_s
35 {
36         transpoly_t *poly;
37         struct translistitem_s *next;
38 }
39 translistitem;
40
41 translistitem translist[MAX_TRANSPOLYS];
42 translistitem *currenttranslist;
43
44 translistitem *translisthash[4096];
45
46 float transviewdist; // distance of view origin along the view normal
47
48 float transreciptable[256];
49
50 void gl_poly_start(void)
51 {
52         int i;
53         transvert = qmalloc(MAX_TRANSVERTS * sizeof(transvert_t));
54         transpoly = qmalloc(MAX_TRANSPOLYS * sizeof(transpoly_t));
55         transpolyindex = qmalloc(MAX_TRANSPOLYS * sizeof(unsigned short));
56         wallvert = qmalloc(MAX_WALLVERTS * sizeof(wallvert_t));
57         wallvertcolor = qmalloc(MAX_WALLVERTS * sizeof(wallvertcolor_t));
58         wallpoly = qmalloc(MAX_WALLPOLYS * sizeof(wallpoly_t));
59         skyvert = qmalloc(MAX_SKYVERTS * sizeof(skyvert_t));
60         skypoly = qmalloc(MAX_SKYPOLYS * sizeof(skypoly_t));
61         transreciptable[0] = 0.0f;
62         for (i = 1;i < 256;i++)
63                 transreciptable[i] = 1.0f / i;
64 }
65
66 void gl_poly_shutdown(void)
67 {
68         qfree(transvert);
69         qfree(transpoly);
70         qfree(transpolyindex);
71         qfree(wallvert);
72         qfree(wallvertcolor);
73         qfree(wallpoly);
74         qfree(skyvert);
75         qfree(skypoly);
76 }
77
78 void gl_poly_newmap(void)
79 {
80         skyavailable_box = false;
81         skyavailable_quake = false;
82         if (!strcmp(skyworldname, cl.worldmodel->name))
83                 skyavailable_quake = true;
84 }
85
86 void GL_Poly_Init(void)
87 {
88         Cmd_AddCommand ("loadsky", &LoadSky_f);
89         Cvar_RegisterVariable (&r_multitexture);
90         Cvar_RegisterVariable (&r_skyquality);
91         Cvar_RegisterVariable (&r_mergesky);
92         R_RegisterModule("GL_Poly", gl_poly_start, gl_poly_shutdown, gl_poly_newmap);
93 }
94
95 void transpolyclear(void)
96 {
97         currenttranspoly = currenttransvert = 0;
98         currenttranslist = translist;
99         memset(translisthash, 0, sizeof(translisthash));
100         transviewdist = DotProduct(r_origin, vpn);
101 }
102
103 // turned into a #define
104 /*
105 void transpolybegin(int texnum, int glowtexnum, int fogtexnum, int transpolytype)
106 {
107         if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
108                 return;
109         transpoly[currenttranspoly].texnum = (unsigned short) texnum;
110         transpoly[currenttranspoly].glowtexnum = (unsigned short) glowtexnum;
111         transpoly[currenttranspoly].fogtexnum = (unsigned short) fogtexnum;
112         transpoly[currenttranspoly].transpolytype = (unsigned short) transpolytype;
113         transpoly[currenttranspoly].firstvert = currenttransvert;
114         transpoly[currenttranspoly].verts = 0;
115 //      transpoly[currenttranspoly].ndist = 0; // clear the normal
116 }
117 */
118
119 // turned into a #define
120 /*
121 void transpolyvert(float x, float y, float z, float s, float t, int r, int g, int b, int a)
122 {
123         int i;
124         if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
125                 return;
126         transvert[currenttransvert].s = s;
127         transvert[currenttransvert].t = t;
128         transvert[currenttransvert].r = bound(0, r, 255);
129         transvert[currenttransvert].g = bound(0, g, 255);
130         transvert[currenttransvert].b = bound(0, b, 255);
131         transvert[currenttransvert].a = bound(0, a, 255);
132         transvert[currenttransvert].v[0] = x;
133         transvert[currenttransvert].v[1] = y;
134         transvert[currenttransvert].v[2] = z;
135         currenttransvert++;
136         transpoly[currenttranspoly].verts++;
137 }
138 */
139
140 void transpolyend(void)
141 {
142         float center, d, maxdist;
143         int i;
144         transvert_t *v;
145         if (currenttranspoly >= MAX_TRANSPOLYS || currenttransvert >= MAX_TRANSVERTS)
146                 return;
147         if (transpoly[currenttranspoly].verts < 3) // skip invalid polygons
148         {
149                 currenttransvert = transpoly[currenttranspoly].firstvert; // reset vert pointer
150                 return;
151         }
152         center = 0;
153         maxdist = -1000000000000000.0f; // eh, it's definitely behind it, so...
154         for (i = 0,v = &transvert[transpoly[currenttranspoly].firstvert];i < transpoly[currenttranspoly].verts;i++, v++)
155         {
156                 d = DotProduct(v->v, vpn);
157                 center += d;
158                 if (d > maxdist)
159                         maxdist = d;
160         }
161         maxdist -= transviewdist;
162         if (maxdist < 4.0f) // behind view
163         {
164                 currenttransvert = transpoly[currenttranspoly].firstvert; // reset vert pointer
165                 return;
166         }
167         center *= transreciptable[transpoly[currenttranspoly].verts];
168         center -= transviewdist;
169         i = bound(0, (int) center, 4095);
170         currenttranslist->next = translisthash[i];
171         currenttranslist->poly = transpoly + currenttranspoly;
172         translisthash[i] = currenttranslist;
173         currenttranslist++;
174         currenttranspoly++;
175 }
176
177 int transpolyindices;
178
179 void transpolyrender(void)
180 {
181         int i, j, tpolytype, texnum;
182         transpoly_t *p;
183         if (!r_render.value)
184                 return;
185         if (currenttranspoly < 1)
186                 return;
187 //      transpolyrenderminmax();
188 //      if (transpolyindices < 1)
189 //              return;
190         // testing
191 //      Con_DPrintf("transpolyrender: %i polys %i infront %i vertices\n", currenttranspoly, transpolyindices, currenttransvert);
192 //      if (transpolyindices >= 2)
193 //              transpolysort();
194         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
195         glEnable(GL_BLEND);
196         glShadeModel(GL_SMOOTH);
197         glDepthMask(0); // disable zbuffer updates
198         glDisable(GL_ALPHA_TEST);
199         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
200         tpolytype = TPOLYTYPE_ALPHA;
201         texnum = -1;
202         /*
203         if (gl_vertexarrays.value)
204         {
205                 // set up the vertex array
206                 glInterleavedArrays(GL_T2F_C4UB_V3F, 0, transvert);
207                 for (i = 0;i < transpolyindices;i++)
208                 {
209                         p = &transpoly[transpolyindex[i]];
210                         if (p->texnum != texnum || p->transpolytype != tpolytype)
211                         {
212                                 if (p->texnum != texnum)
213                                 {
214                                         texnum = p->texnum;
215                                         glBindTexture(GL_TEXTURE_2D, texnum);
216                                 }
217                                 if (p->transpolytype != tpolytype)
218                                 {
219                                         tpolytype = p->transpolytype;
220                                         if (tpolytype == TPOLYTYPE_ADD) // additive
221                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
222                                         else // alpha
223                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
224                                 }
225                         }
226                         glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
227                         if (p->glowtexnum)
228                         {
229                                 texnum = p->glowtexnum; // highly unlikely to match next poly, but...
230                                 glBindTexture(GL_TEXTURE_2D, texnum);
231                                 tpolytype = TPOLYTYPE_ADD; // might match next poly
232                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
233                                 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
234                         }
235                 }
236                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
237                 glDisableClientState(GL_COLOR_ARRAY);
238                 glDisableClientState(GL_VERTEX_ARRAY);
239         }
240         else
241         */
242         {
243                 int points = -1;
244                 translistitem *item;
245                 transvert_t *vert;
246                 for (i = 4095;i >= 0;i--)
247                 {
248                         item = translisthash[i];
249                         while (item)
250                         {
251                                 p = item->poly;
252                                 item = item->next;
253                                 if (p->texnum != texnum || p->verts != points || p->transpolytype != tpolytype)
254                                 {
255                                         glEnd();
256                                         if (isG200)
257                                         {
258                                                 // LordHavoc: Matrox G200 cards can't handle per pixel alpha
259                                                 if (p->fogtexnum)
260                                                         glEnable(GL_ALPHA_TEST);
261                                                 else
262                                                         glDisable(GL_ALPHA_TEST);
263                                         }
264                                         if (p->texnum != texnum)
265                                         {
266                                                 texnum = p->texnum;
267                                                 glBindTexture(GL_TEXTURE_2D, texnum);
268                                         }
269                                         if (p->transpolytype != tpolytype)
270                                         {
271                                                 tpolytype = p->transpolytype;
272                                                 if (tpolytype == TPOLYTYPE_ADD) // additive
273                                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
274                                                 else // alpha
275                                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
276                                         }
277                                         points = p->verts;
278                                         switch (points)
279                                         {
280                                         case 3:
281                                                 glBegin(GL_TRIANGLES);
282                                                 break;
283                                         case 4:
284                                                 glBegin(GL_QUADS);
285                                                 break;
286                                         default:
287                                                 glBegin(GL_POLYGON);
288                                                 points = -1; // to force a reinit on the next poly
289                                                 break;
290                                         }
291                                 }
292                                 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
293                                 {
294                                         // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
295                                         glTexCoord2f(vert->s, vert->t);
296                                         // again, vector version isn't supported I think
297                                         glColor4ub(vert->r, vert->g, vert->b, vert->a);
298                                         glVertex3fv(vert->v);
299                                 }
300                                 if (p->glowtexnum)
301                                 {
302                                         glEnd();
303                                         texnum = p->glowtexnum; // highly unlikely to match next poly, but...
304                                         glBindTexture(GL_TEXTURE_2D, texnum);
305                                         if (tpolytype != TPOLYTYPE_ADD)
306                                         {
307                                                 tpolytype = TPOLYTYPE_ADD; // might match next poly
308                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
309                                         }
310                                         points = -1;
311                                         glBegin(GL_POLYGON);
312                                         for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
313                                         {
314                                                 glColor4ub(255,255,255,vert->a);
315                                                 // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
316                                                 glTexCoord2f(vert->s, vert->t);
317                                                 glVertex3fv(vert->v);
318                                         }
319                                         glEnd();
320                                 }
321                                 if (fogenabled && p->transpolytype == TPOLYTYPE_ALPHA)
322                                 {
323                                         vec3_t diff;
324                                         glEnd();
325                                         points = -1; // to force a reinit on the next poly
326                                         if (tpolytype != TPOLYTYPE_ALPHA)
327                                         {
328                                                 tpolytype = TPOLYTYPE_ALPHA; // probably matchs next poly
329                                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
330                                         }
331                                         if (p->fogtexnum)
332                                         {
333                                                 if (texnum != p->fogtexnum) // highly unlikely to match next poly, but...
334                                                 {
335                                                         texnum = p->fogtexnum;
336                                                         glBindTexture(GL_TEXTURE_2D, texnum);
337                                                 }
338                                                 glBegin(GL_POLYGON);
339                                                 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
340                                                 {
341                                                         VectorSubtract(vert->v, r_origin, diff);
342                                                         glTexCoord2f(vert->s, vert->t);
343                                                         glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
344                                                         glVertex3fv(vert->v);
345                                                 }
346                                                 glEnd ();
347                                         }
348                                         else
349                                         {
350                                                 glDisable(GL_TEXTURE_2D);
351                                                 glBegin(GL_POLYGON);
352                                                 for (j = 0,vert = &transvert[p->firstvert];j < p->verts;j++, vert++)
353                                                 {
354                                                         VectorSubtract(vert->v, r_origin, diff);
355                                                         glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], vert->a*(1.0f/255.0f)*exp(fogdensity/DotProduct(diff,diff)));
356                                                         glVertex3fv(vert->v);
357                                                 }
358                                                 glEnd ();
359                                                 glEnable(GL_TEXTURE_2D);
360                                         }
361                                 }
362                         }
363                 }
364                 glEnd();
365         }
366
367         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
368         glDepthMask(1); // enable zbuffer updates
369         glDisable(GL_ALPHA_TEST);
370 }
371
372 void wallpolyclear(void)
373 {
374         currentwallpoly = currentwallvert = 0;
375 }
376
377 void wallpolyrender(void)
378 {
379         int i, j, texnum, lighttexnum;
380         wallpoly_t *p;
381         wallvert_t *vert;
382         wallvertcolor_t *vertcolor;
383         if (!r_render.value)
384                 return;
385         if (currentwallpoly < 1)
386                 return;
387         c_brush_polys += currentwallpoly;
388         // testing
389         //Con_DPrintf("wallpolyrender: %i polys %i vertices\n", currentwallpoly, currentwallvert);
390         if (!gl_mtexable)
391                 r_multitexture.value = 0;
392         glDisable(GL_BLEND);
393         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
394         glShadeModel(GL_FLAT);
395         // make sure zbuffer is enabled
396         glEnable(GL_DEPTH_TEST);
397 //      glDisable(GL_ALPHA_TEST);
398         glDepthMask(1);
399         glColor3f(1,1,1);
400         if (r_fullbright.value) // LordHavoc: easy to do fullbright...
401         {
402                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
403                 texnum = -1;
404                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
405                 {
406                         if (p->texnum != texnum)
407                         {
408                                 texnum = p->texnum;
409                                 glBindTexture(GL_TEXTURE_2D, texnum);
410                         }
411                         vert = &wallvert[p->firstvert];
412                         glBegin(GL_POLYGON);
413                         for (j=0 ; j<p->numverts ; j++, vert++)
414                         {
415                                 glTexCoord2f (vert->vert[3], vert->vert[4]);
416                                 glVertex3fv (vert->vert);
417                         }
418                         glEnd ();
419                 }
420         }
421         else if (r_multitexture.value)
422         {
423                 if (gl_combine.value)
424                 {
425                         qglActiveTexture(GL_TEXTURE0_ARB);
426                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
427                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
428                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
429                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
430                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
431                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
432                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
433                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
434                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
435                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
436                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE);
437                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_TEXTURE);
438                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
439                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
440                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
441                         glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0);
442                         glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);
443                         glEnable(GL_TEXTURE_2D);
444                         qglActiveTexture(GL_TEXTURE1_ARB);
445                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
446                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
447                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
448                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
449                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
450                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
451                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
452                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
453                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
454                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
455                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
456                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_TEXTURE);
457                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
458                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
459                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
460                         glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 4.0);
461                         glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);
462                         glEnable(GL_TEXTURE_2D);
463                 }
464                 else
465                 {
466                         qglActiveTexture(GL_TEXTURE0_ARB);
467                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
468                         glEnable(GL_TEXTURE_2D);
469                         qglActiveTexture(GL_TEXTURE1_ARB);
470                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
471                         glEnable(GL_TEXTURE_2D);
472                 }
473                 texnum = -1;
474                 lighttexnum = -1;
475                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
476                 {
477                         if (p->texnum != texnum)
478                         {
479                                 texnum = p->texnum;
480                                 qglActiveTexture(GL_TEXTURE0_ARB);
481                                 glBindTexture(GL_TEXTURE_2D, texnum);
482                                 qglActiveTexture(GL_TEXTURE1_ARB);
483                         }
484                         if (p->lighttexnum != lighttexnum)
485                         {
486                                 lighttexnum = p->lighttexnum;
487                                 glBindTexture(GL_TEXTURE_2D, lighttexnum);
488                         }
489                         vert = &wallvert[p->firstvert];
490                         glBegin(GL_POLYGON);
491                         for (j=0 ; j<p->numverts ; j++, vert++)
492                         {
493                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB, vert->vert[3], vert->vert[4]); // texture
494                                 qglMultiTexCoord2f(GL_TEXTURE1_ARB, vert->vert[5], vert->vert[6]); // lightmap
495                                 glVertex3fv (vert->vert);
496                         }
497                         glEnd ();
498                 }
499
500                 qglActiveTexture(GL_TEXTURE1_ARB);
501                 glDisable(GL_TEXTURE_2D);
502                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
503                 qglActiveTexture(GL_TEXTURE0_ARB);
504                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
505         }
506         else
507         {
508                 // first do the textures
509                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
510                 texnum = -1;
511                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
512                 {
513                         if (p->texnum != texnum)
514                         {
515                                 texnum = p->texnum;
516                                 glBindTexture(GL_TEXTURE_2D, texnum);
517                         }
518                         vert = &wallvert[p->firstvert];
519                         glBegin(GL_POLYGON);
520                         for (j=0 ; j<p->numverts ; j++, vert++)
521                         {
522                                 glTexCoord2f (vert->vert[3], vert->vert[4]);
523                                 glVertex3fv (vert->vert);
524                         }
525                         glEnd ();
526                 }
527                 // then modulate using the lightmaps
528                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
529                 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
530                 glEnable(GL_BLEND);
531                 texnum = -1;
532                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
533                 {
534                         if (p->lighttexnum != texnum)
535                         {
536                                 texnum = p->lighttexnum;
537                                 glBindTexture(GL_TEXTURE_2D, texnum);
538                         }
539                         vert = &wallvert[p->firstvert];
540                         glBegin(GL_POLYGON);
541                         for (j=0 ; j<p->numverts ; j++, vert++)
542                         {
543                                 glTexCoord2f (vert->vert[5], vert->vert[6]);
544                                 glVertex3fv (vert->vert);
545                         }
546                         glEnd ();
547                 }
548         }
549         // switch to additive mode settings
550         glDepthMask(0);
551         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
552         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
553         glEnable(GL_BLEND);
554 //      glDisable(GL_ALPHA_TEST);
555         glShadeModel(GL_SMOOTH);
556         // render vertex lit overlays ontop
557         texnum = -1;
558         for (i = 0, p = wallpoly;i < currentwallpoly;i++, p++)
559         {
560                 if (!p->lit)
561                         continue;
562                 for (j = 0,vertcolor = &wallvertcolor[p->firstvert];j < p->numverts;j++, vertcolor++)
563                         if (vertcolor->r || vertcolor->g || vertcolor->b)
564                                 goto lit;
565                 continue;
566 lit:
567                 c_light_polys++;
568                 if (p->texnum != texnum)
569                 {
570                         texnum = p->texnum;
571                         glBindTexture(GL_TEXTURE_2D, texnum);
572                 }
573                 glBegin(GL_POLYGON);
574                 for (j = 0,vert = &wallvert[p->firstvert], vertcolor = &wallvertcolor[p->firstvert];j < p->numverts;j++, vert++, vertcolor++)
575                 {
576                         // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
577                         glTexCoord2f(vert->vert[3], vert->vert[4]);
578                         // again, vector version isn't supported I think
579                         glColor3ub(vertcolor->r, vertcolor->g, vertcolor->b);
580                         glVertex3fv(vert->vert);
581                 }
582                 glEnd();
583         }
584         // render glow textures
585         glShadeModel(GL_FLAT);
586         glBlendFunc(GL_ONE, GL_ONE);
587         if (lighthalf)
588                 glColor3f(0.5,0.5,0.5);
589         else
590                 glColor3f(1,1,1);
591         texnum = -1;
592         for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
593         {
594                 if (!p->glowtexnum)
595                         continue;
596                 if (p->glowtexnum != texnum)
597                 {
598                         texnum = p->glowtexnum;
599                         glBindTexture(GL_TEXTURE_2D, texnum);
600                 }
601                 vert = &wallvert[p->firstvert];
602                 glBegin(GL_POLYGON);
603                 for (j=0 ; j<p->numverts ; j++, vert++)
604                 {
605                         glTexCoord2f (vert->vert[3], vert->vert[4]);
606                         glVertex3fv (vert->vert);
607                 }
608                 glEnd();
609         }
610         glColor3f(1,1,1);
611         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
612         glShadeModel(GL_SMOOTH);
613         if (fogenabled)
614         {
615                 vec3_t diff;
616                 glDisable(GL_TEXTURE_2D);
617                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
618                 {
619                         vert = &wallvert[p->firstvert];
620                         glBegin(GL_POLYGON);
621                         for (j=0 ; j<p->numverts ; j++, vert++)
622                         {
623                                 VectorSubtract(vert->vert, r_origin, diff);
624                                 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
625                                 glVertex3fv (vert->vert);
626                         }
627                         glEnd ();
628                 }
629                 glEnable(GL_TEXTURE_2D);
630         }
631         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
632         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
633 //      glDisable(GL_ALPHA_TEST);
634         glShadeModel(GL_SMOOTH);
635         glDisable(GL_BLEND);
636         glDepthMask(1);
637 }
638
639 static int skyrendersphere;
640 static int skyrenderbox;
641 static int skyrenderglquakepolys;
642 static int skyrendertwolayers;
643 static int skyrendercombine;
644
645 void skypolyclear(void)
646 {
647         currentskypoly = currentskyvert = 0;
648         skyrendersphere = false;
649         skyrenderbox = false;
650         skyrenderglquakepolys = false;
651         skyrendertwolayers = false;
652         skyrendercombine = false;
653         if (r_skyquality.value >= 1 && !fogenabled)
654         {
655                 if (skyavailable_box)
656                         skyrenderbox = true;
657                 else if (skyavailable_quake)
658                 {
659                         switch((int) r_skyquality.value)
660                         {
661                         case 1:
662                                 skyrenderglquakepolys = true;
663                                 break;
664                         case 2:
665                                 skyrenderglquakepolys = true;
666                                 skyrendertwolayers = true;
667                                 if (gl_combine.value)
668                                         skyrendercombine = true;
669                                 break;
670                         case 3:
671                                 skyrendersphere = true;
672                                 break;
673                         default:
674                         case 4:
675                                 skyrendersphere = true;
676                                 skyrendertwolayers = true;
677                                 if (gl_combine.value)
678                                         skyrendercombine = true;
679                                 break;
680                         }
681                 }
682         }
683         if (r_mergesky.value && (skyrenderglquakepolys || skyrendersphere))
684         {
685                 skyrendertwolayers = false;
686                 skyrendercombine = false;
687 //              R_BuildSky((int) (cl.time * 8.0), (int) (cl.time * 16.0));
688 //              R_BuildSky((int) (cl.time * -8.0), 0);
689                 R_BuildSky(0, (int) (cl.time * 8.0));
690         }
691
692 }
693
694 void skypolyrender(void)
695 {
696         int i, j;
697         skypoly_t *p;
698         skyvert_t *vert;
699         float length, speedscale;
700         vec3_t dir;
701         float y, number;
702         if (!r_render.value)
703                 return;
704         if (currentskypoly < 1)
705                 return;
706 //      glDisable(GL_ALPHA_TEST);
707         glDisable(GL_BLEND);
708         // make sure zbuffer is enabled
709         glEnable(GL_DEPTH_TEST);
710         glDepthMask(1);
711         glVertexPointer(3, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].v[0]);
712         glEnableClientState(GL_VERTEX_ARRAY);
713         GL_LockArray(0, currentskyvert);
714         speedscale = cl.time * (8.0/128.0);
715         speedscale -= (int)speedscale;
716         for (vert = skyvert, j = 0;j < currentskyvert;j++, vert++)
717         {
718                 VectorSubtract (vert->v, r_origin, dir);
719                 // flatten the sphere
720                 dir[2] *= 3;
721
722                 // LordHavoc: fast version
723                 number = DotProduct(dir, dir);
724                 *((long *)&y) = 0x5f3759df - ((* (long *) &number) >> 1);
725                 length = 3.0f * (y * (1.5f - (number * 0.5f * y * y)));
726                 // LordHavoc: slow version
727                 //length = 3.0f / sqrt(DotProduct(dir, dir));
728
729                 vert->tex2[0] = speedscale + (vert->tex[0] = speedscale + dir[0] * length);
730                 vert->tex2[1] = speedscale + (vert->tex[1] = speedscale + dir[1] * length);
731         }
732
733         glDisable(GL_BLEND);
734         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
735
736         if (skyrenderglquakepolys)
737         {
738                 glTexCoordPointer(2, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].tex[0]);
739                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
740
741                 if (skyrendercombine)
742                 {
743                         // upper clouds
744                         glBindTexture(GL_TEXTURE_2D, R_GetTexture(lighthalf ? solidskytexture_half : solidskytexture));
745
746                         // set up the second texcoord array
747                         // switch texcoord array selector to TMU 1
748                         qglClientActiveTexture(GL_TEXTURE1_ARB);
749                         glTexCoordPointer(2, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].tex2[0]);
750                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
751
752                         // render both layers as one pass using GL_ARB_texture_env_combine
753                         // TMU 0 is already selected, the TMU 0 texcoord array is already
754                         // set up, the texture is bound, and texturing is already enabled,
755                         // so just set up COMBINE
756
757                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
758
759                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
760                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
761                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
762                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
763                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
764                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
765                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
766
767                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
768                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
769                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE);
770                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_TEXTURE);
771                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
772                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
773                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
774
775                         glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0);
776                         glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);
777
778                         // set up TMU 1
779                         qglActiveTexture(GL_TEXTURE1_ARB);
780                         // lower clouds
781                         glBindTexture(GL_TEXTURE_2D, R_GetTexture(lighthalf ? alphaskytexture_half : alphaskytexture));
782
783                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
784
785                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB);
786                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
787                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
788                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
789                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
790                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
791                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);
792
793                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
794                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);
795                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE);
796                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_TEXTURE);
797                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
798                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
799                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
800
801                         glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0);
802                         glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);
803                         glEnable(GL_TEXTURE_2D);
804
805                         // draw it
806                         for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
807                                 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
808
809                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
810                         glDisable(GL_TEXTURE_2D);
811                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
812                         qglActiveTexture(GL_TEXTURE0_ARB);
813                         // switch texcoord array selector back to TMU 0
814                         qglClientActiveTexture(GL_TEXTURE0_ARB);
815                         // the TMU 0 texcoord array is disabled by the code below
816                 }
817                 else
818                 {
819                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
820                         if (r_mergesky.value)
821                                 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture)); // both layers in one texture
822                         else
823                                 glBindTexture(GL_TEXTURE_2D, R_GetTexture(solidskytexture)); // upper clouds
824                         if(lighthalf)
825                                 glColor3f(0.5f, 0.5f, 0.5f);
826                         else
827                                 glColor3f(1.0f,1.0f,1.0f);
828                         glEnable(GL_TEXTURE_2D);
829                         GL_LockArray(0, currentskyvert);
830                         for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
831                                 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
832                         GL_UnlockArray();
833                         if (skyrendertwolayers)
834                         {
835                                 glEnable(GL_BLEND);
836                                 glDepthMask(0);
837                                 glBindTexture(GL_TEXTURE_2D, R_GetTexture(alphaskytexture)); // lower clouds
838                                 // switch to lower clouds texcoord array
839                                 glTexCoordPointer(2, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].tex2[0]);
840                                 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
841                                         glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
842                                 glDepthMask(1);
843                                 glDisable(GL_BLEND);
844                         }
845                         glColor3f(1,1,1);
846                 }
847                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
848         }
849         else
850         {
851                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
852                 glDisable(GL_TEXTURE_2D);
853                 // note: this color is not seen if skyrendersphere or skyrenderbox is on
854                 glColor3fv(fogcolor);
855                 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
856                         glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
857                 glColor3f(1,1,1);
858                 glEnable(GL_TEXTURE_2D);
859         }
860         GL_UnlockArray();
861         glDisableClientState(GL_VERTEX_ARRAY);
862 }
863
864 static char skyname[256];
865
866 /*
867 ==================
868 R_SetSkyBox
869 ==================
870 */
871 char    *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
872 rtexture_t *skyboxside[6];
873 int R_SetSkyBox(char *sky)
874 {
875         int             i;
876         char    name[1024];
877         byte*   image_rgba;
878
879         if (strcmp(sky, skyname) == 0) // no change
880                 return true;
881
882         if (strlen(sky) > 1000)
883         {
884                 Con_Printf ("sky name too long (%i, max is 1000)\n", strlen(sky));
885                 return false;
886         }
887
888         skyboxside[0] = skyboxside[1] = skyboxside[2] = skyboxside[3] = skyboxside[4] = skyboxside[5] = NULL;
889         skyavailable_box = false;
890         skyname[0] = 0;
891
892         if (!sky[0])
893                 return true;
894
895         for (i = 0;i < 6;i++)
896         {
897                 sprintf (name, "env/%s%s", sky, suf[i]);
898                 if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
899                 {
900                         sprintf (name, "gfx/env/%s%s", sky, suf[i]);
901                         if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
902                         {
903                                 Con_Printf ("Couldn't load %s\n", name);
904                                 continue;
905                         }
906                 }
907                 skyboxside[i] = R_LoadTexture(va("skyboxside%d", i), image_width, image_height, image_rgba, TEXF_RGBA | TEXF_PRECACHE);
908                 qfree(image_rgba);
909         }
910
911         if (skyboxside[0] || skyboxside[1] || skyboxside[2] || skyboxside[3] || skyboxside[4] || skyboxside[5])
912         {
913                 skyavailable_box = true;
914                 strcpy(skyname, sky);
915                 return true;
916         }
917         return false;
918 }
919
920 // LordHavoc: added LoadSky console command
921 void LoadSky_f (void)
922 {
923         switch (Cmd_Argc())
924         {
925         case 1:
926                 if (skyname[0])
927                         Con_Printf("current sky: %s\n", skyname);
928                 else
929                         Con_Printf("no skybox has been set\n");
930                 break;
931         case 2:
932                 if (R_SetSkyBox(Cmd_Argv(1)))
933                 {
934                         if (skyname[0])
935                                 Con_Printf("skybox set to %s\n", skyname);
936                         else
937                                 Con_Printf("skybox disabled\n");
938                 }
939                 else
940                         Con_Printf("failed to load skybox %s\n", Cmd_Argv(1));
941                 break;
942         default:
943                 Con_Printf("usage: loadsky skyname\n");
944                 break;
945         }
946 }
947
948 #define R_SkyBoxPolyVec(s,t,x,y,z) \
949         glTexCoord2f((s) * (254.0f/256.0f) + (1.0f/256.0f), (t) * (254.0f/256.0f) + (1.0f/256.0f));\
950         glVertex3f((x) * 1024.0 + r_origin[0], (y) * 1024.0 + r_origin[1], (z) * 1024.0 + r_origin[2]);
951
952 void R_SkyBox(void)
953 {
954         glDisable(GL_DEPTH_TEST);
955         glDepthMask(0);
956         glDisable (GL_BLEND);
957         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
958         if (lighthalf)
959                 glColor3f(0.5,0.5,0.5);
960         else
961                 glColor3f(1,1,1);
962         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[3])); // front
963         glBegin(GL_QUADS);
964         R_SkyBoxPolyVec(1, 0,  1, -1,  1);
965         R_SkyBoxPolyVec(1, 1,  1, -1, -1);
966         R_SkyBoxPolyVec(0, 1,  1,  1, -1);
967         R_SkyBoxPolyVec(0, 0,  1,  1,  1);
968         glEnd();
969         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[1])); // back
970         glBegin(GL_QUADS);
971         R_SkyBoxPolyVec(1, 0, -1,  1,  1);
972         R_SkyBoxPolyVec(1, 1, -1,  1, -1);
973         R_SkyBoxPolyVec(0, 1, -1, -1, -1);
974         R_SkyBoxPolyVec(0, 0, -1, -1,  1);
975         glEnd();
976         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[0])); // right
977         glBegin(GL_QUADS);
978         R_SkyBoxPolyVec(1, 0,  1,  1,  1);
979         R_SkyBoxPolyVec(1, 1,  1,  1, -1);
980         R_SkyBoxPolyVec(0, 1, -1,  1, -1);
981         R_SkyBoxPolyVec(0, 0, -1,  1,  1);
982         glEnd();
983         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[2])); // left
984         glBegin(GL_QUADS);
985         R_SkyBoxPolyVec(1, 0, -1, -1,  1);
986         R_SkyBoxPolyVec(1, 1, -1, -1, -1);
987         R_SkyBoxPolyVec(0, 1,  1, -1, -1);
988         R_SkyBoxPolyVec(0, 0,  1, -1,  1);
989         glEnd();
990         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[4])); // up
991         glBegin(GL_QUADS);
992         R_SkyBoxPolyVec(1, 0,  1, -1,  1);
993         R_SkyBoxPolyVec(1, 1,  1,  1,  1);
994         R_SkyBoxPolyVec(0, 1, -1,  1,  1);
995         R_SkyBoxPolyVec(0, 0, -1, -1,  1);
996         glEnd();
997         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[5])); // down
998         glBegin(GL_QUADS);
999         R_SkyBoxPolyVec(1, 0,  1,  1, -1);
1000         R_SkyBoxPolyVec(1, 1,  1, -1, -1);
1001         R_SkyBoxPolyVec(0, 1, -1, -1, -1);
1002         R_SkyBoxPolyVec(0, 0, -1,  1, -1);
1003         glEnd();
1004         glDepthMask(1);
1005         glEnable (GL_DEPTH_TEST);
1006         glColor3f (1,1,1);
1007 }
1008
1009 float skysphere[33*33*5];
1010 int skysphereindices[32*32*6];
1011 void skyspherecalc(float *sphere, float dx, float dy, float dz)
1012 {
1013         float a, b, x, ax, ay, v[3], length;
1014         int i, j, *index;
1015         for (a = 0;a <= 1;a += (1.0 / 32.0))
1016         {
1017                 ax = cos(a * M_PI * 2);
1018                 ay = -sin(a * M_PI * 2);
1019                 for (b = 0;b <= 1;b += (1.0 / 32.0))
1020                 {
1021                         x = cos(b * M_PI * 2);
1022                         v[0] = ax*x * dx;
1023                         v[1] = ay*x * dy;
1024                         v[2] = -sin(b * M_PI * 2) * dz;
1025                         length = 3.0f / sqrt(v[0]*v[0]+v[1]*v[1]+(v[2]*v[2]*9));
1026                         *sphere++ = v[0] * length;
1027                         *sphere++ = v[1] * length;
1028                         *sphere++ = v[0];
1029                         *sphere++ = v[1];
1030                         *sphere++ = v[2];
1031                 }
1032         }
1033         index = skysphereindices;
1034         for (j = 0;j < 32;j++)
1035         {
1036                 for (i = 0;i < 32;i++)
1037                 {
1038                         *index++ =  j      * 33 + i;
1039                         *index++ =  j      * 33 + i + 1;
1040                         *index++ = (j + 1) * 33 + i;
1041
1042                         *index++ =  j      * 33 + i + 1;
1043                         *index++ = (j + 1) * 33 + i + 1;
1044                         *index++ = (j + 1) * 33 + i;
1045                 }
1046                 i++;
1047         }
1048 }
1049
1050 void skyspherearrays(float *vert, float *tex, float *tex2, float *source, float s, float s2)
1051 {
1052         float *v, *t, *t2;
1053         int i;
1054         v = vert;
1055         t = tex;
1056         t2 = tex2;
1057         for (i = 0;i < (33*33);i++)
1058         {
1059                 *t++ = source[0] + s;
1060                 *t++ = source[1] + s;
1061                 *t2++ = source[0] + s2;
1062                 *t2++ = source[1] + s2;
1063                 *v++ = source[2] + r_origin[0];
1064                 *v++ = source[3] + r_origin[1];
1065                 *v++ = source[4] + r_origin[2];
1066                 *v++ = 0;
1067                 source += 5;
1068         }
1069 }
1070
1071 void R_SkySphere(void)
1072 {
1073         float speedscale, speedscale2;
1074         float vert[33*33*4], tex[33*33*2], tex2[33*33*2];
1075         static qboolean skysphereinitialized = false;
1076         if (!skysphereinitialized)
1077         {
1078                 skysphereinitialized = true;
1079                 skyspherecalc(skysphere, 1024, 1024, 1024 / 3);
1080         }
1081         glDisable(GL_DEPTH_TEST);
1082         glDepthMask(0);
1083         glDisable (GL_BLEND);
1084         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1085         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1086         if (lighthalf)
1087                 glColor3f(0.5,0.5,0.5);
1088         else
1089                 glColor3f(1,1,1);
1090         speedscale = cl.time*8.0/128.0;
1091         speedscale -= (int)speedscale;
1092         speedscale2 = cl.time*16.0/128.0;
1093         speedscale2 -= (int)speedscale2;
1094         skyspherearrays(vert, tex, tex2, skysphere, speedscale, speedscale2);
1095         glVertexPointer(3, GL_FLOAT, sizeof(float) * 4, vert);
1096         glEnableClientState(GL_VERTEX_ARRAY);
1097         // do not lock the texcoord array, because it will be switched
1098         GL_LockArray(0, 32*32*6);
1099         glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, tex);
1100         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1101         if (r_mergesky.value)
1102         {
1103                 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture)); // both layers in one texture
1104                 glDrawElements(GL_TRIANGLES, 32*32*6, GL_UNSIGNED_INT, &skysphereindices[0]);
1105         }
1106         else
1107         {
1108                 // LordHavoc: note that this combine operation does not use the color,
1109                 // so it has to use alternate textures in lighthalf mode
1110                 if (skyrendercombine)
1111                 {
1112                         // upper clouds
1113                         glBindTexture(GL_TEXTURE_2D, R_GetTexture(lighthalf ? solidskytexture_half : solidskytexture));
1114
1115                         // set up the second texcoord array
1116                         // switch texcoord array selector to TMU 1
1117                         qglClientActiveTexture(GL_TEXTURE1_ARB);
1118                         glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, tex2);
1119                         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1120
1121
1122                         // render both layers as one pass using GL_ARB_texture_env_combine
1123                         // TMU 0 is already selected, the TMU 0 texcoord array is already
1124                         // set up, the texture is bound, and texturing is already enabled,
1125                         // so just set up COMBINE
1126
1127                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
1128
1129                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
1130                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
1131                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
1132                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
1133                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
1134                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
1135                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
1136
1137                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
1138                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
1139                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE);
1140                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_TEXTURE);
1141                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
1142                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
1143                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
1144
1145                         glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0);
1146                         glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);
1147
1148                         // set up TMU 1
1149                         qglActiveTexture(GL_TEXTURE1_ARB);
1150                         // lower clouds
1151                         glBindTexture(GL_TEXTURE_2D, R_GetTexture(lighthalf ? alphaskytexture_half : alphaskytexture));
1152
1153                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
1154
1155                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB);
1156                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
1157                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
1158                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
1159                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
1160                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
1161                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);
1162
1163                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
1164                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);
1165                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE);
1166                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_TEXTURE);
1167                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
1168                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
1169                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);
1170
1171                         glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0);
1172                         glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);
1173                         glEnable(GL_TEXTURE_2D);
1174
1175                         // draw it
1176                         glDrawElements(GL_TRIANGLES, 32*32*6, GL_UNSIGNED_INT, &skysphereindices[0]);
1177
1178                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1179                         glDisable(GL_TEXTURE_2D);
1180                         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1181                         qglActiveTexture(GL_TEXTURE0_ARB);
1182                         // switch texcoord array selector back to TMU 0
1183                         qglClientActiveTexture(GL_TEXTURE0_ARB);
1184                         // the TMU 0 texcoord array is disabled by the code below
1185                 }
1186                 else
1187                 {
1188                         glBindTexture(GL_TEXTURE_2D, R_GetTexture(solidskytexture)); // upper clouds
1189                         glDrawElements(GL_TRIANGLES, 32*32*6, GL_UNSIGNED_INT, &skysphereindices[0]);
1190
1191                         if (skyrendertwolayers)
1192                         {
1193                                 glEnable (GL_BLEND);
1194                                 glBindTexture(GL_TEXTURE_2D, R_GetTexture(alphaskytexture)); // lower clouds
1195                                 glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, tex2);
1196                                 glDrawElements(GL_TRIANGLES, 32*32*6, GL_UNSIGNED_INT, &skysphereindices[0]);
1197                                 glDisable (GL_BLEND);
1198                         }
1199                 }
1200         }
1201         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1202         GL_UnlockArray();
1203         glDisableClientState(GL_VERTEX_ARRAY);
1204         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1205         glDepthMask(1);
1206         glEnable (GL_DEPTH_TEST);
1207         glColor3f (1,1,1);
1208 }
1209
1210 void R_Sky(void)
1211 {
1212         if (!r_render.value)
1213                 return;
1214         if (skyrendersphere)
1215                 R_SkySphere();
1216         else if (skyrenderbox)
1217                 R_SkyBox();
1218 }
1219
1220 //===============================================================
1221
1222 byte skyupperlayerpixels[128*128*4];
1223 byte skylowerlayerpixels[128*128*4];
1224 byte skymergedpixels[128*128*4];
1225
1226 void R_BuildSky (int scrollupper, int scrolllower)
1227 {
1228         int x, y, ux, uy, lx, ly;
1229         byte *m, *u, *l;
1230         m = skymergedpixels;
1231         for (y = 0;y < 128;y++)
1232         {
1233                 uy = (y + scrollupper) & 127;
1234                 ly = (y + scrolllower) & 127;
1235                 for (x = 0;x < 128;x++)
1236                 {
1237                         ux = (x + scrollupper) & 127;
1238                         lx = (x + scrolllower) & 127;
1239                         u = &skyupperlayerpixels[(uy * 128 + ux) * 4];
1240                         l = &skylowerlayerpixels[(ly * 128 + lx) * 4];
1241                         if (l[3])
1242                         {
1243                                 if (l[3] == 255)
1244                                         *((int *)m) = *((int *)l);
1245                                 else
1246                                 {
1247                                         m[0] = ((((int) l[0] - (int) u[0]) * (int) l[3]) >> 8) + (int) u[0];
1248                                         m[1] = ((((int) l[1] - (int) u[1]) * (int) l[3]) >> 8) + (int) u[1];
1249                                         m[2] = ((((int) l[2] - (int) u[2]) * (int) l[3]) >> 8) + (int) u[2];
1250                                         m[3] = 255;
1251                                 }
1252                         }
1253                         else
1254                                 *((int *)m) = *((int *)u);
1255                         m += 4;
1256                 }
1257         }
1258         // FIXME: implement generated texture callbacks to speed this up?  (skip identifier lookup, CRC, memcpy, etc)
1259         if (mergeskytexture)
1260         {
1261                 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture));
1262                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, skymergedpixels);
1263         }
1264         else
1265                 mergeskytexture = R_LoadTexture("mergedskytexture", 128, 128, skymergedpixels, TEXF_RGBA | TEXF_ALWAYSPRECACHE);
1266 }
1267
1268 /*
1269 =============
1270 R_InitSky
1271
1272 A sky texture is 256*128, with the right side being a masked overlay
1273 ==============
1274 */
1275 void R_InitSky (byte *src, int bytesperpixel)
1276 {
1277         int                     i, j, p;
1278         unsigned        trans[128*128];
1279         unsigned        transpix;
1280         int                     r, g, b;
1281         unsigned        *rgba;
1282
1283         if (!isworldmodel)
1284                 return;
1285
1286         strcpy(skyworldname, loadmodel->name);
1287         if (bytesperpixel == 4)
1288         {
1289                 for (i = 0;i < 128;i++)
1290                         for (j = 0;j < 128;j++)
1291                                 trans[(i*128) + j] = src[i*256+j+128];
1292         }
1293         else
1294         {
1295                 // make an average value for the back to avoid
1296                 // a fringe on the top level
1297                 r = g = b = 0;
1298                 for (i=0 ; i<128 ; i++)
1299                 {
1300                         for (j=0 ; j<128 ; j++)
1301                         {
1302                                 p = src[i*256 + j + 128];
1303                                 rgba = &d_8to24table[p];
1304                                 trans[(i*128) + j] = *rgba;
1305                                 r += ((byte *)rgba)[0];
1306                                 g += ((byte *)rgba)[1];
1307                                 b += ((byte *)rgba)[2];
1308                         }
1309                 }
1310
1311                 ((byte *)&transpix)[0] = r/(128*128);
1312                 ((byte *)&transpix)[1] = g/(128*128);
1313                 ((byte *)&transpix)[2] = b/(128*128);
1314                 ((byte *)&transpix)[3] = 0;
1315         }
1316
1317         memcpy(skyupperlayerpixels, trans, 128*128*4);
1318
1319         solidskytexture = R_LoadTexture ("sky_solidtexture", 128, 128, (byte *) trans, TEXF_RGBA | TEXF_PRECACHE);
1320         for (i = 0;i < 128*128;i++)
1321         {
1322                 ((byte *)&trans[i])[0] >>= 1;
1323                 ((byte *)&trans[i])[1] >>= 1;
1324                 ((byte *)&trans[i])[2] >>= 1;
1325         }
1326         solidskytexture_half = R_LoadTexture ("sky_solidtexture_half", 128, 128, (byte *) trans, TEXF_RGBA | TEXF_PRECACHE);
1327
1328         if (bytesperpixel == 4)
1329         {
1330                 for (i = 0;i < 128;i++)
1331                         for (j = 0;j < 128;j++)
1332                                 trans[(i*128) + j] = src[i*256+j];
1333         }
1334         else
1335         {
1336                 for (i=0 ; i<128 ; i++)
1337                 {
1338                         for (j=0 ; j<128 ; j++)
1339                         {
1340                                 p = src[i*256 + j];
1341                                 if (p == 0)
1342                                         trans[(i*128) + j] = transpix;
1343                                 else
1344                                         trans[(i*128) + j] = d_8to24table[p];
1345                         }
1346                 }
1347         }
1348
1349         memcpy(skylowerlayerpixels, trans, 128*128*4);
1350
1351         alphaskytexture = R_LoadTexture ("sky_alphatexture", 128, 128, (byte *) trans, TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
1352         for (i = 0;i < 128*128;i++)
1353         {
1354                 ((byte *)&trans[i])[0] >>= 1;
1355                 ((byte *)&trans[i])[1] >>= 1;
1356                 ((byte *)&trans[i])[2] >>= 1;
1357         }
1358         alphaskytexture_half = R_LoadTexture ("sky_alphatexture_half", 128, 128, (byte *) trans, TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
1359 }