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