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