added CVAR_SAVE and CVAR_NOTIFY flags to cvar_t structure (at the beginning), updated...
[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 char skyworldname[1024];
26 rtexture_t *mergeskytexture;
27 rtexture_t *solidskytexture;
28 rtexture_t *alphaskytexture;
29 qboolean skyavailable_quake;
30 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                 qglSelectTexture(gl_mtex_enum+0);
424                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
425                 glEnable(GL_TEXTURE_2D);
426                 qglSelectTexture(gl_mtex_enum+1);
427                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
428                 glEnable(GL_TEXTURE_2D);
429                 texnum = -1;
430                 lighttexnum = -1;
431                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
432                 {
433                         if (p->texnum != texnum || p->lighttexnum != lighttexnum)
434                         {
435                                 texnum = p->texnum;
436                                 lighttexnum = p->lighttexnum;
437                                 qglSelectTexture(gl_mtex_enum+0);
438                                 glBindTexture(GL_TEXTURE_2D, texnum);
439                                 qglSelectTexture(gl_mtex_enum+1);
440                                 glBindTexture(GL_TEXTURE_2D, lighttexnum);
441                         }
442                         vert = &wallvert[p->firstvert];
443                         glBegin(GL_POLYGON);
444                         for (j=0 ; j<p->numverts ; j++, vert++)
445                         {
446                                 qglMTexCoord2f(gl_mtex_enum, vert->vert[3], vert->vert[4]); // texture
447                                 qglMTexCoord2f((gl_mtex_enum+1), vert->vert[5], vert->vert[6]); // lightmap
448                                 glVertex3fv (vert->vert);
449                         }
450                         glEnd ();
451                 }
452
453                 qglSelectTexture(gl_mtex_enum+1);
454                 glDisable(GL_TEXTURE_2D);
455                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
456                 qglSelectTexture(gl_mtex_enum+0);
457                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
458         }
459         else
460         {
461                 // first do the textures
462                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
463                 texnum = -1;
464                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
465                 {
466                         if (p->texnum != texnum)
467                         {
468                                 texnum = p->texnum;
469                                 glBindTexture(GL_TEXTURE_2D, texnum);
470                         }
471                         vert = &wallvert[p->firstvert];
472                         glBegin(GL_POLYGON);
473                         for (j=0 ; j<p->numverts ; j++, vert++)
474                         {
475                                 glTexCoord2f (vert->vert[3], vert->vert[4]);
476                                 glVertex3fv (vert->vert);
477                         }
478                         glEnd ();
479                 }
480                 // then modulate using the lightmaps
481                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
482                 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
483                 glEnable(GL_BLEND);
484                 texnum = -1;
485                 for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
486                 {
487                         if (p->lighttexnum != texnum)
488                         {
489                                 texnum = p->lighttexnum;
490                                 glBindTexture(GL_TEXTURE_2D, texnum);
491                         }
492                         vert = &wallvert[p->firstvert];
493                         glBegin(GL_POLYGON);
494                         for (j=0 ; j<p->numverts ; j++, vert++)
495                         {
496                                 glTexCoord2f (vert->vert[5], vert->vert[6]);
497                                 glVertex3fv (vert->vert);
498                         }
499                         glEnd ();
500                 }
501         }
502         // switch to additive mode settings
503         glDepthMask(0);
504         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
505         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
506         glEnable(GL_BLEND);
507 //      glDisable(GL_ALPHA_TEST);
508         glShadeModel(GL_SMOOTH);
509         // render vertex lit overlays ontop
510         texnum = -1;
511         for (i = 0, p = wallpoly;i < currentwallpoly;i++, p++)
512         {
513                 if (!p->lit)
514                         continue;
515                 for (j = 0,vertcolor = &wallvertcolor[p->firstvert];j < p->numverts;j++, vertcolor++)
516                         if (vertcolor->r || vertcolor->g || vertcolor->b)
517                                 goto lit;
518                 continue;
519 lit:
520                 c_light_polys++;
521                 if (p->texnum != texnum)
522                 {
523                         texnum = p->texnum;
524                         glBindTexture(GL_TEXTURE_2D, texnum);
525                 }
526                 glBegin(GL_POLYGON);
527                 for (j = 0,vert = &wallvert[p->firstvert], vertcolor = &wallvertcolor[p->firstvert];j < p->numverts;j++, vert++, vertcolor++)
528                 {
529                         // would be 2fv, but windoze Matrox G200 and probably G400 drivers don't support that (dumb...)
530                         glTexCoord2f(vert->vert[3], vert->vert[4]);
531                         // again, vector version isn't supported I think
532                         glColor3ub(vertcolor->r, vertcolor->g, vertcolor->b);
533                         glVertex3fv(vert->vert);
534                 }
535                 glEnd();
536         }
537         // render glow textures
538         glShadeModel(GL_FLAT);
539         glBlendFunc(GL_ONE, GL_ONE);
540         if (lighthalf)
541                 glColor3f(0.5,0.5,0.5);
542         else
543                 glColor3f(1,1,1);
544         texnum = -1;
545         for (i = 0,p = wallpoly;i < currentwallpoly;i++, p++)
546         {
547                 if (!p->glowtexnum)
548                         continue;
549                 if (p->glowtexnum != texnum)
550                 {
551                         texnum = p->glowtexnum;
552                         glBindTexture(GL_TEXTURE_2D, texnum);
553                 }
554                 vert = &wallvert[p->firstvert];
555                 glBegin(GL_POLYGON);
556                 for (j=0 ; j<p->numverts ; j++, vert++)
557                 {
558                         glTexCoord2f (vert->vert[3], vert->vert[4]);
559                         glVertex3fv (vert->vert);
560                 }
561                 glEnd();
562         }
563         glColor3f(1,1,1);
564         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
565         glShadeModel(GL_SMOOTH);
566         if (fogenabled)
567         {
568                 vec3_t diff;
569                 glDisable(GL_TEXTURE_2D);
570                 for (i = 0,p = &wallpoly[0];i < currentwallpoly;i++, p++)
571                 {
572                         vert = &wallvert[p->firstvert];
573                         glBegin(GL_POLYGON);
574                         for (j=0 ; j<p->numverts ; j++, vert++)
575                         {
576                                 VectorSubtract(vert->vert, r_origin, diff);
577                                 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
578                                 glVertex3fv (vert->vert);
579                         }
580                         glEnd ();
581                 }
582                 glEnable(GL_TEXTURE_2D);
583         }
584         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
585         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
586 //      glDisable(GL_ALPHA_TEST);
587         glShadeModel(GL_SMOOTH);
588         glDisable(GL_BLEND);
589         glDepthMask(1);
590 }
591
592 int skyrendersphere;
593 int skyrenderbox;
594 int skyrenderglquakepolys;
595 int skyrendertwolayers;
596
597 void skypolyclear(void)
598 {
599         currentskypoly = currentskyvert = 0;
600         skyrendersphere = false;
601         skyrenderbox = false;
602         skyrenderglquakepolys = false;
603         skyrendertwolayers = false;
604         if (r_skyquality.value >= 1 && !fogenabled)
605         {
606                 if (skyavailable_box)
607                         skyrenderbox = true;
608                 else if (skyavailable_quake)
609                 {
610                         switch((int) r_skyquality.value)
611                         {
612                         case 1:
613                                 skyrenderglquakepolys = true;
614                                 break;
615                         case 2:
616                                 skyrenderglquakepolys = true;
617                                 skyrendertwolayers = true;
618                                 break;
619                         case 3:
620                                 skyrendersphere = true;
621                                 break;
622                         default:
623                         case 4:
624                                 skyrendersphere = true;
625                                 skyrendertwolayers = true;
626                                 break;
627                         }
628                 }
629         }
630         if (r_mergesky.value && (skyrenderglquakepolys || skyrendersphere))
631         {
632                 skyrendertwolayers = false;
633 //              R_BuildSky((int) (cl.time * 8.0), (int) (cl.time * 16.0));
634 //              R_BuildSky((int) (cl.time * -8.0), 0);
635                 R_BuildSky(0, (int) (cl.time * 8.0));
636         }
637
638 }
639
640 void skypolyrender(void)
641 {
642         int i, j;
643         skypoly_t *p;
644         skyvert_t *vert;
645         float length, speedscale;
646         vec3_t dir;
647         if (!r_render.value)
648                 return;
649         if (currentskypoly < 1)
650                 return;
651 //      glDisable(GL_ALPHA_TEST);
652         glDisable(GL_BLEND);
653         // make sure zbuffer is enabled
654         glEnable(GL_DEPTH_TEST);
655         glDepthMask(1);
656         if (skyrenderglquakepolys)
657         {
658                 if (r_mergesky.value)
659                         glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture)); // both layers in one texture
660                 else
661                         glBindTexture(GL_TEXTURE_2D, R_GetTexture(solidskytexture)); // upper clouds
662                 glTexCoordPointer(2, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].tex[0]);
663                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
664                 glVertexPointer(3, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].v[0]);
665                 glEnableClientState(GL_VERTEX_ARRAY);
666                 if(lighthalf)
667                         glColor3f(0.5f, 0.5f, 0.5f);
668                 else
669                         glColor3f(1.0f,1.0f,1.0f);
670                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
671                 glEnable(GL_TEXTURE_2D);
672                 glDisable(GL_BLEND);
673                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
674                 if (r_mergesky.value)
675                 {
676                         speedscale = cl.time * (8.0/128.0);
677                         speedscale -= (int)speedscale;
678                 }
679                 else
680                 {
681                         speedscale = cl.time * (8.0/128.0);
682                         speedscale -= (int)speedscale;
683                 }
684                 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
685                 {
686                         vert = skyvert + p->firstvert;
687                         for (j = 0;j < p->verts;j++, vert++)
688                         {
689                                 VectorSubtract (vert->v, r_origin, dir);
690                                 // flatten the sphere
691                                 dir[2] *= 3;
692
693                                 length = 3.0f / sqrt(DotProduct(dir, dir));
694
695                                 vert->tex[0] = speedscale + dir[0] * length;
696                                 vert->tex[1] = speedscale + dir[1] * length;
697                         }
698                 }
699                 GL_LockArray(0, currentskyvert);
700                 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
701                         glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
702                 GL_UnlockArray();
703                 if (skyrendertwolayers)
704                 {
705                         glEnable(GL_BLEND);
706                         glDepthMask(0);
707                         glBindTexture(GL_TEXTURE_2D, R_GetTexture(alphaskytexture)); // lower clouds
708                         speedscale = cl.time * (16.0 / 128.0);
709                         speedscale -= (int)speedscale;
710                         for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
711                         {
712                                 vert = skyvert + p->firstvert;
713                                 for (j = 0;j < p->verts;j++, vert++)
714                                 {
715                                         VectorSubtract (vert->v, r_origin, dir);
716                                         // flatten the sphere
717                                         dir[2] *= 3;
718
719                                         length = 3.0f / sqrt(DotProduct(dir, dir));
720
721                                         vert->tex[0] = speedscale + dir[0] * length;
722                                         vert->tex[1] = speedscale + dir[1] * length;
723                                 }
724                         }
725                         GL_LockArray(0, currentskyvert);
726                         for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
727                                 glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
728                         GL_UnlockArray();
729                         glDisable(GL_BLEND);
730                 }
731                 glColor3f(1,1,1);
732                 glDepthMask(1);
733                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
734                 glDisableClientState(GL_VERTEX_ARRAY);
735         }
736         else
737         {
738                 glVertexPointer(3, GL_FLOAT, sizeof(skyvert_t), &skyvert[0].v[0]);
739                 glEnableClientState(GL_VERTEX_ARRAY);
740                 glDisable(GL_TEXTURE_2D);
741                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
742                 // note: this color is not seen if skyrendersphere or skyrenderbox is on
743                 glColor3fv(fogcolor);
744                 GL_LockArray(0, currentskyvert);
745                 for (i = 0, p = &skypoly[0];i < currentskypoly;i++, p++)
746                         glDrawArrays(GL_POLYGON, p->firstvert, p->verts);
747                 GL_UnlockArray();
748                 glColor3f(1,1,1);
749                 glEnable(GL_TEXTURE_2D);
750                 glDisableClientState(GL_VERTEX_ARRAY);
751         }
752 }
753
754 static char skyname[256];
755
756 /*
757 ==================
758 R_SetSkyBox
759 ==================
760 */
761 char    *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
762 rtexture_t *skyboxside[6];
763 int R_SetSkyBox(char *sky)
764 {
765         int             i;
766         char    name[1024];
767         byte*   image_rgba;
768
769         if (strcmp(sky, skyname) == 0) // no change
770                 return true;
771
772         if (strlen(sky) > 1000)
773         {
774                 Con_Printf ("sky name too long (%i, max is 1000)\n", strlen(sky));
775                 return false;
776         }
777
778         skyboxside[0] = skyboxside[1] = skyboxside[2] = skyboxside[3] = skyboxside[4] = skyboxside[5] = NULL;
779         skyavailable_box = false;
780         skyname[0] = 0;
781
782         if (!sky[0])
783                 return true;
784
785         for (i = 0;i < 6;i++)
786         {
787                 sprintf (name, "env/%s%s", sky, suf[i]);
788                 if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
789                 {
790                         sprintf (name, "gfx/env/%s%s", sky, suf[i]);
791                         if (!(image_rgba = loadimagepixels(name, false, 0, 0)))
792                         {
793                                 Con_Printf ("Couldn't load %s\n", name);
794                                 continue;
795                         }
796                 }
797                 skyboxside[i] = R_LoadTexture(va("skyboxside%d", i), image_width, image_height, image_rgba, TEXF_RGBA | TEXF_PRECACHE);
798                 qfree(image_rgba);
799         }
800
801         if (skyboxside[0] || skyboxside[1] || skyboxside[2] || skyboxside[3] || skyboxside[4] || skyboxside[5])
802         {
803                 skyavailable_box = true;
804                 strcpy(skyname, sky);
805                 return true;
806         }
807         return false;
808 }
809
810 // LordHavoc: added LoadSky console command
811 void LoadSky_f (void)
812 {
813         switch (Cmd_Argc())
814         {
815         case 1:
816                 if (skyname[0])
817                         Con_Printf("current sky: %s\n", skyname);
818                 else
819                         Con_Printf("no skybox has been set\n");
820                 break;
821         case 2:
822                 if (R_SetSkyBox(Cmd_Argv(1)))
823                 {
824                         if (skyname[0])
825                                 Con_Printf("skybox set to %s\n", skyname);
826                         else
827                                 Con_Printf("skybox disabled\n");
828                 }
829                 else
830                         Con_Printf("failed to load skybox %s\n", Cmd_Argv(1));
831                 break;
832         default:
833                 Con_Printf("usage: loadsky skyname\n");
834                 break;
835         }
836 }
837
838 #define R_SkyBoxPolyVec(s,t,x,y,z) \
839         glTexCoord2f((s) * (254.0f/256.0f) + (1.0f/256.0f), (t) * (254.0f/256.0f) + (1.0f/256.0f));\
840         glVertex3f((x) * 1024.0 + r_origin[0], (y) * 1024.0 + r_origin[1], (z) * 1024.0 + r_origin[2]);
841
842 void R_SkyBox(void)
843 {
844         glDisable(GL_DEPTH_TEST);
845         glDepthMask(0);
846         glDisable (GL_BLEND);
847         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
848         if (lighthalf)
849                 glColor3f(0.5,0.5,0.5);
850         else
851                 glColor3f(1,1,1);
852         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[3])); // front
853         glBegin(GL_QUADS);
854         R_SkyBoxPolyVec(1, 0,  1, -1,  1);
855         R_SkyBoxPolyVec(1, 1,  1, -1, -1);
856         R_SkyBoxPolyVec(0, 1,  1,  1, -1);
857         R_SkyBoxPolyVec(0, 0,  1,  1,  1);
858         glEnd();
859         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[1])); // back
860         glBegin(GL_QUADS);
861         R_SkyBoxPolyVec(1, 0, -1,  1,  1);
862         R_SkyBoxPolyVec(1, 1, -1,  1, -1);
863         R_SkyBoxPolyVec(0, 1, -1, -1, -1);
864         R_SkyBoxPolyVec(0, 0, -1, -1,  1);
865         glEnd();
866         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[0])); // right
867         glBegin(GL_QUADS);
868         R_SkyBoxPolyVec(1, 0,  1,  1,  1);
869         R_SkyBoxPolyVec(1, 1,  1,  1, -1);
870         R_SkyBoxPolyVec(0, 1, -1,  1, -1);
871         R_SkyBoxPolyVec(0, 0, -1,  1,  1);
872         glEnd();
873         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[2])); // left
874         glBegin(GL_QUADS);
875         R_SkyBoxPolyVec(1, 0, -1, -1,  1);
876         R_SkyBoxPolyVec(1, 1, -1, -1, -1);
877         R_SkyBoxPolyVec(0, 1,  1, -1, -1);
878         R_SkyBoxPolyVec(0, 0,  1, -1,  1);
879         glEnd();
880         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[4])); // up
881         glBegin(GL_QUADS);
882         R_SkyBoxPolyVec(1, 0,  1, -1,  1);
883         R_SkyBoxPolyVec(1, 1,  1,  1,  1);
884         R_SkyBoxPolyVec(0, 1, -1,  1,  1);
885         R_SkyBoxPolyVec(0, 0, -1, -1,  1);
886         glEnd();
887         glBindTexture(GL_TEXTURE_2D, R_GetTexture(skyboxside[5])); // down
888         glBegin(GL_QUADS);
889         R_SkyBoxPolyVec(1, 0,  1,  1, -1);
890         R_SkyBoxPolyVec(1, 1,  1, -1, -1);
891         R_SkyBoxPolyVec(0, 1, -1, -1, -1);
892         R_SkyBoxPolyVec(0, 0, -1,  1, -1);
893         glEnd();
894         glDepthMask(1);
895         glEnable (GL_DEPTH_TEST);
896         glColor3f (1,1,1);
897 }
898
899 float skysphereouter[33*33*5];
900 float skysphereinner[33*33*5];
901 int skysphereindices[32*32*6];
902 void skyspherecalc(float *sphere, float dx, float dy, float dz)
903 {
904         float a, b, x, ax, ay, v[3], length;
905         int i, j, *index;
906         for (a = 0;a <= 1;a += (1.0 / 32.0))
907         {
908                 ax = cos(a * M_PI * 2);
909                 ay = -sin(a * M_PI * 2);
910                 for (b = 0;b <= 1;b += (1.0 / 32.0))
911                 {
912                         x = cos(b * M_PI * 2);
913                         v[0] = ax*x * dx;
914                         v[1] = ay*x * dy;
915                         v[2] = -sin(b * M_PI * 2) * dz;
916                         length = 3.0f / sqrt(v[0]*v[0]+v[1]*v[1]+(v[2]*v[2]*9));
917                         *sphere++ = v[0] * length;
918                         *sphere++ = v[1] * length;
919                         *sphere++ = v[0];
920                         *sphere++ = v[1];
921                         *sphere++ = v[2];
922                 }
923         }
924         index = skysphereindices;
925         for (j = 0;j < 32;j++)
926         {
927                 for (i = 0;i < 32;i++)
928                 {
929                         *index++ =  j      * 33 + i;
930                         *index++ =  j      * 33 + i + 1;
931                         *index++ = (j + 1) * 33 + i;
932
933                         *index++ =  j      * 33 + i + 1;
934                         *index++ = (j + 1) * 33 + i + 1;
935                         *index++ = (j + 1) * 33 + i;
936                 }
937                 i++;
938         }
939 }
940
941 void skysphere(float *source, float s)
942 {
943         float vert[33*33][4], tex[33*33][2], *v, *t;
944         int i;
945         v = &vert[0][0];
946         t = &tex[0][0];
947         for (i = 0;i < (33*33);i++)
948         {
949                 *t++ = *source++ + s;
950                 *t++ = *source++ + s;
951                 *v++ = *source++ + r_origin[0];
952                 *v++ = *source++ + r_origin[1];
953                 *v++ = *source++ + r_origin[2];
954                 *v++ = 0;
955         }
956         glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, tex);
957         glVertexPointer(3, GL_FLOAT, sizeof(float) * 4, vert);
958         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
959         glEnableClientState(GL_VERTEX_ARRAY);
960         GL_LockArray(0, 32*32*6);
961         glDrawElements(GL_TRIANGLES, 32*32*6, GL_UNSIGNED_INT, &skysphereindices[0]);
962         GL_UnlockArray();
963         glDisableClientState(GL_VERTEX_ARRAY);
964         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
965 }
966
967 void R_SkySphere(void)
968 {
969         float speedscale;
970         static qboolean skysphereinitialized = false;
971         if (!skysphereinitialized)
972         {
973                 skysphereinitialized = true;
974                 skyspherecalc(skysphereouter, 1024, 1024, 1024 / 3);
975                 skyspherecalc(skysphereinner, 1024, 1024, 1024 / 3);
976         }
977         glDisable(GL_DEPTH_TEST);
978         glDepthMask(0);
979         glDisable (GL_BLEND);
980         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
981         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
982         if (lighthalf)
983                 glColor3f(0.5,0.5,0.5);
984         else
985                 glColor3f(1,1,1);
986         if (r_mergesky.value)
987         {
988                 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture)); // both layers in one texture
989                 speedscale = cl.time*8.0/128.0;
990                 speedscale -= (int)speedscale;
991                 skysphere(skysphereouter, speedscale);
992         }
993         else
994         {
995                 glBindTexture(GL_TEXTURE_2D, R_GetTexture(solidskytexture)); // upper clouds
996                 speedscale = cl.time*8.0/128.0;
997                 speedscale -= (int)speedscale;
998                 skysphere(skysphereouter, speedscale);
999                 if (skyrendertwolayers)
1000                 {
1001                         glEnable (GL_BLEND);
1002                         glBindTexture(GL_TEXTURE_2D, R_GetTexture(alphaskytexture)); // lower clouds
1003                         speedscale = cl.time*16.0/128.0;
1004                         speedscale -= (int)speedscale;
1005                         skysphere(skysphereinner, speedscale);
1006                         glDisable (GL_BLEND);
1007                 }
1008         }
1009         glDepthMask(1);
1010         glEnable (GL_DEPTH_TEST);
1011         glColor3f (1,1,1);
1012 }
1013
1014 void R_Sky(void)
1015 {
1016         if (!r_render.value)
1017                 return;
1018         if (skyrendersphere)
1019                 R_SkySphere();
1020         else if (skyrenderbox)
1021                 R_SkyBox();
1022 }
1023
1024 //===============================================================
1025
1026 byte skyupperlayerpixels[128*128*4];
1027 byte skylowerlayerpixels[128*128*4];
1028 byte skymergedpixels[128*128*4];
1029
1030 void R_BuildSky (int scrollupper, int scrolllower)
1031 {
1032         int x, y, ux, uy, lx, ly;
1033         byte *m, *u, *l;
1034         m = skymergedpixels;
1035         for (y = 0;y < 128;y++)
1036         {
1037                 uy = (y + scrollupper) & 127;
1038                 ly = (y + scrolllower) & 127;
1039                 for (x = 0;x < 128;x++)
1040                 {
1041                         ux = (x + scrollupper) & 127;
1042                         lx = (x + scrolllower) & 127;
1043                         u = &skyupperlayerpixels[(uy * 128 + ux) * 4];
1044                         l = &skylowerlayerpixels[(ly * 128 + lx) * 4];
1045                         if (l[3])
1046                         {
1047                                 if (l[3] == 255)
1048                                         *((int *)m) = *((int *)l);
1049                                 else
1050                                 {
1051                                         m[0] = ((((int) l[0] - (int) u[0]) * (int) l[3]) >> 8) + (int) u[0];
1052                                         m[1] = ((((int) l[1] - (int) u[1]) * (int) l[3]) >> 8) + (int) u[1];
1053                                         m[2] = ((((int) l[2] - (int) u[2]) * (int) l[3]) >> 8) + (int) u[2];
1054                                         m[3] = 255;
1055                                 }
1056                         }
1057                         else
1058                                 *((int *)m) = *((int *)u);
1059                         m += 4;
1060                 }
1061         }
1062         // FIXME: implement generated texture callbacks to speed this up?  (skip identifier lookup, CRC, memcpy, etc)
1063         if (mergeskytexture)
1064         {
1065                 glBindTexture(GL_TEXTURE_2D, R_GetTexture(mergeskytexture));
1066                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, skymergedpixels);
1067         }
1068         else
1069                 mergeskytexture = R_LoadTexture("mergedskytexture", 128, 128, skymergedpixels, TEXF_RGBA | TEXF_ALWAYSPRECACHE);
1070 }
1071
1072 /*
1073 =============
1074 R_InitSky
1075
1076 A sky texture is 256*128, with the right side being a masked overlay
1077 ==============
1078 */
1079 void R_InitSky (byte *src, int bytesperpixel)
1080 {
1081         int                     i, j, p;
1082         unsigned        trans[128*128];
1083         unsigned        transpix;
1084         int                     r, g, b;
1085         unsigned        *rgba;
1086
1087         if (!isworldmodel)
1088                 return;
1089
1090         strcpy(skyworldname, loadmodel->name);
1091         if (bytesperpixel == 4)
1092         {
1093                 for (i = 0;i < 128;i++)
1094                         for (j = 0;j < 128;j++)
1095                                 trans[(i*128) + j] = src[i*256+j+128];
1096         }
1097         else
1098         {
1099                 // make an average value for the back to avoid
1100                 // a fringe on the top level
1101                 r = g = b = 0;
1102                 for (i=0 ; i<128 ; i++)
1103                 {
1104                         for (j=0 ; j<128 ; j++)
1105                         {
1106                                 p = src[i*256 + j + 128];
1107                                 rgba = &d_8to24table[p];
1108                                 trans[(i*128) + j] = *rgba;
1109                                 r += ((byte *)rgba)[0];
1110                                 g += ((byte *)rgba)[1];
1111                                 b += ((byte *)rgba)[2];
1112                         }
1113                 }
1114
1115                 ((byte *)&transpix)[0] = r/(128*128);
1116                 ((byte *)&transpix)[1] = g/(128*128);
1117                 ((byte *)&transpix)[2] = b/(128*128);
1118                 ((byte *)&transpix)[3] = 0;
1119         }
1120
1121         memcpy(skyupperlayerpixels, trans, 128*128*4);
1122
1123         solidskytexture = R_LoadTexture ("sky_solidtexture", 128, 128, (byte *) trans, TEXF_RGBA | TEXF_PRECACHE);
1124
1125         if (bytesperpixel == 4)
1126         {
1127                 for (i = 0;i < 128;i++)
1128                         for (j = 0;j < 128;j++)
1129                                 trans[(i*128) + j] = src[i*256+j];
1130         }
1131         else
1132         {
1133                 for (i=0 ; i<128 ; i++)
1134                 {
1135                         for (j=0 ; j<128 ; j++)
1136                         {
1137                                 p = src[i*256 + j];
1138                                 if (p == 0)
1139                                         trans[(i*128) + j] = transpix;
1140                                 else
1141                                         trans[(i*128) + j] = d_8to24table[p];
1142                         }
1143                 }
1144         }
1145
1146         memcpy(skylowerlayerpixels, trans, 128*128*4);
1147
1148         alphaskytexture = R_LoadTexture ("sky_alphatexture", 128, 128, (byte *) trans, TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
1149 }