]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rsurf.c
increased build number, changed default lightmap format to RGB (higher quality in...
[divverent/darkplaces.git] / gl_rsurf.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_surf.c: surface-related refresh code
21
22 #include "quakedef.h"
23
24 extern int                     skytexturenum;
25
26 int             lightmap_textures;
27
28 signed blocklights[18*18*3]; // LordHavoc: *3 for colored lighting
29
30 // LordHavoc: skinny but tall lightmaps for quicker subimage uploads
31 #define BLOCK_WIDTH             128
32 #define BLOCK_HEIGHT    128
33 // LordHavoc: increased lightmap limit from 64 to 1024
34 #define MAX_LIGHTMAPS   1024
35 #define LIGHTMAPSIZE    (BLOCK_WIDTH*BLOCK_HEIGHT*4)
36
37 int                     active_lightmaps;
38
39 short allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
40
41 byte *lightmaps[MAX_LIGHTMAPS];
42 short lightmapupdate[MAX_LIGHTMAPS][2];
43
44 int lightmapalign, lightmapalignmask; // LordHavoc: NVIDIA's broken subimage fix, see BuildLightmaps for notes
45 cvar_t gl_lightmapalign = {"gl_lightmapalign", "4"};
46 cvar_t gl_lightmaprgba = {"gl_lightmaprgba", "0"};
47 cvar_t gl_nosubimagefragments = {"gl_nosubimagefragments", "0"};
48 cvar_t gl_nosubimage = {"gl_nosubimage", "0"};
49 cvar_t r_ambient = {"r_ambient", "0"};
50 cvar_t gl_vertex = {"gl_vertex", "0"};
51 //cvar_t gl_funnywalls = {"gl_funnywalls", "0"}; // LordHavoc: see BuildSurfaceDisplayList
52
53 qboolean lightmaprgba, nosubimagefragments, nosubimage;
54 int lightmapbytes;
55
56 qboolean skyisvisible;
57 extern qboolean gl_arrays;
58
59 extern int r_dlightframecount;
60
61 void glrsurf_init()
62 {
63         int i;
64         for (i = 0;i < MAX_LIGHTMAPS;i++)
65                 lightmaps[i] = NULL;
66         Cvar_RegisterVariable(&gl_lightmapalign);
67         Cvar_RegisterVariable(&gl_lightmaprgba);
68         Cvar_RegisterVariable(&gl_nosubimagefragments);
69         Cvar_RegisterVariable(&gl_nosubimage);
70         Cvar_RegisterVariable(&r_ambient);
71 //      Cvar_RegisterVariable(&gl_funnywalls);
72         Cvar_RegisterVariable(&gl_vertex);
73         // check if it's the glquake minigl driver
74         if (strncasecmp(gl_vendor,"3Dfx",4)==0)
75         if (!gl_arrays)
76         {
77 //              Cvar_SetValue("gl_nosubimagefragments", 1);
78 //              Cvar_SetValue("gl_nosubimage", 1);
79                 Cvar_SetValue("gl_lightmode", 0);
80         }
81 }
82
83 extern qboolean lighthalf;
84 /*
85 ===============
86 R_BuildLightMap
87
88 Combine and scale multiple lightmaps into the 8.8 format in blocklights
89 ===============
90 */
91 void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
92 {
93         int                     smax, tmax;
94         int                     t;
95         int                     i, j, size;
96         byte            *lightmap;
97         int                     scale;
98         int                     maps;
99         int                     *bl;
100
101         surf->cached_lighthalf = lighthalf;
102         surf->cached_ambient = r_ambient.value;
103
104         smax = (surf->extents[0]>>4)+1;
105         tmax = (surf->extents[1]>>4)+1;
106         size = smax*tmax;
107         lightmap = surf->samples;
108
109 // set to full bright if no light data
110         if (currententity->effects & EF_FULLBRIGHT || !cl.worldmodel->lightdata)
111         {
112                 bl = blocklights;
113                 for (i=0 ; i<size ; i++)
114                 {
115                         *bl++ = 255*256;
116                         *bl++ = 255*256;
117                         *bl++ = 255*256;
118                 }
119         }
120         else
121         {
122 // clear to no light
123                 bl = blocklights;
124                 j = r_ambient.value * 512.0f; // would be 256.0f logically, but using 512.0f to match winquake style
125                 for (i=0 ; i<size ; i++)
126                 {
127                         *bl++ = j;
128                         *bl++ = j;
129                         *bl++ = j;
130                 }
131
132 // add all the lightmaps
133                 if (lightmap)
134                         for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
135                         {
136                                 scale = d_lightstylevalue[surf->styles[maps]];
137                                 surf->cached_light[maps] = scale;       // 8.8 fraction
138                                 bl = blocklights;
139                                 for (i=0 ; i<size ; i++)
140                                 {
141                                         *bl++ += *lightmap++ * scale;
142                                         *bl++ += *lightmap++ * scale;
143                                         *bl++ += *lightmap++ * scale;
144                                 }
145                         }
146         }
147         stride -= (smax*lightmapbytes);
148         bl = blocklights;
149         if (lighthalf)
150         {
151                 // LordHavoc: I shift down by 8 unlike GLQuake's 7,
152                 // the image is brightened as a processing pass
153                 if (lightmaprgba)
154                 {
155                         for (i=0 ; i<tmax ; i++, dest += stride)
156                         {
157                                 for (j=0 ; j<smax ; j++)
158                                 {
159                                         t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
160                                         t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
161                                         t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
162                                         *dest++ = 255;
163                                 }
164                         }
165                 }
166                 else
167                 {
168                         for (i=0 ; i<tmax ; i++, dest += stride)
169                         {
170                                 for (j=0 ; j<smax ; j++)
171                                 {
172                                         t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
173                                         t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
174                                         t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
175                                 }
176                         }
177                 }
178         }
179         else
180         {
181                 if (lightmaprgba)
182                 {
183                         for (i=0 ; i<tmax ; i++, dest += stride)
184                         {
185                                 for (j=0 ; j<smax ; j++)
186                                 {
187                                         t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
188                                         t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
189                                         t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
190                                         *dest++ = 255;
191                                 }
192                         }
193                 }
194                 else
195                 {
196                         for (i=0 ; i<tmax ; i++, dest += stride)
197                         {
198                                 for (j=0 ; j<smax ; j++)
199                                 {
200                                         t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
201                                         t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
202                                         t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
203                                 }
204                         }
205                 }
206         }
207 }
208
209 byte templight[32*32*4];
210
211 void R_UpdateLightmap(msurface_t *s, int lnum)
212 {
213         int smax, tmax;
214         // upload the new lightmap texture fragment
215         glBindTexture(GL_TEXTURE_2D, lightmap_textures + lnum);
216         if (nosubimage || nosubimagefragments)
217         {
218                 if (lightmapupdate[lnum][0] > s->light_t)
219                         lightmapupdate[lnum][0] = s->light_t;
220                 if (lightmapupdate[lnum][1] < (s->light_t + ((s->extents[1]>>4)+1)))
221                         lightmapupdate[lnum][1] = (s->light_t + ((s->extents[1]>>4)+1));
222                 if (lightmaprgba)
223                         R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 4, BLOCK_WIDTH * 4);
224                 else
225                         R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 3, BLOCK_WIDTH * 3);
226         }
227         else
228         {
229                 smax = ((s->extents[0]>>4)+lightmapalign) & lightmapalignmask;
230                 tmax = (s->extents[1]>>4)+1;
231                 if (lightmaprgba)
232                 {
233                         R_BuildLightMap (s, templight, smax * 4);
234                         glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
235                 }
236                 else
237                 {
238                         R_BuildLightMap (s, templight, smax * 3);
239                         glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
240                 }
241         }
242 }
243
244
245 /*
246 ===============
247 R_TextureAnimation
248
249 Returns the proper texture for a given time and base texture
250 ===============
251 */
252 texture_t *R_TextureAnimation (texture_t *base)
253 {
254         texture_t *original;
255         int             relative;
256         int             count;
257
258         if (currententity->frame)
259         {
260                 if (base->alternate_anims)
261                         base = base->alternate_anims;
262         }
263         
264         if (!base->anim_total)
265                 return base;
266
267         original = base;
268
269         relative = (int)(cl.time*10) % base->anim_total;
270
271         count = 0;      
272         while (base->anim_min > relative || base->anim_max <= relative)
273         {
274                 base = base->anim_next;
275                 if (!base)
276                 {
277                         Con_Printf("R_TextureAnimation: broken cycle");
278                         return original;
279                 }
280                 if (++count > 100)
281                 {
282                         Con_Printf("R_TextureAnimation: infinite cycle");
283                         return original;
284                 }
285         }
286
287         return base;
288 }
289
290
291 /*
292 =============================================================
293
294         BRUSH MODELS
295
296 =============================================================
297 */
298
299
300 extern  int             solidskytexture;
301 extern  int             alphaskytexture;
302 extern  float   speedscale;             // for top sky and bottom sky
303
304 qboolean mtexenabled = false;
305
306 extern char skyname[];
307
308 void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits);
309 //extern cvar_t r_dynamicwater;
310 float   turbsin[256] =
311 {
312         #include "gl_warp_sin.h"
313 };
314 #define TURBSCALE (256.0 / (2 * M_PI))
315
316
317 void UploadLightmaps()
318 {
319         int i;
320         if (nosubimage || nosubimagefragments)
321         {
322                 for (i = 0;i < MAX_LIGHTMAPS;i++)
323                 {
324                         if (lightmapupdate[i][0] < lightmapupdate[i][1])
325                         {
326                                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
327                                 if (nosubimage)
328                                 {
329                                         if (lightmaprgba)
330                                                 glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
331                                         else
332                                                 glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
333                                 }
334                                 else
335                                 {
336                                         if (lightmaprgba)
337                                                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lightmapupdate[i][0], BLOCK_WIDTH, lightmapupdate[i][1] - lightmapupdate[i][0], GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i] + (BLOCK_WIDTH * 4 * lightmapupdate[i][0]));
338                                         else
339                                                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lightmapupdate[i][0], BLOCK_WIDTH, lightmapupdate[i][1] - lightmapupdate[i][0], GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i] + (BLOCK_WIDTH * 3 * lightmapupdate[i][0]));
340                                 }
341                         }
342                         lightmapupdate[i][0] = BLOCK_HEIGHT;
343                         lightmapupdate[i][1] = 0;
344                 }
345         }
346 }
347
348 void R_SkySurf(msurface_t *s, qboolean transform)
349 {
350         glpoly_t *p;
351         int i;
352         float *v;
353         for (p=s->polys ; p ; p=p->next)
354         {
355                 if (currentskypoly < MAX_SKYPOLYS && currentskyvert + p->numverts <= MAX_SKYVERTS)
356                 {
357                         skypoly[currentskypoly].firstvert = currentskyvert;
358                         skypoly[currentskypoly++].verts = p->numverts;
359                         if (transform)
360                         {
361                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
362                                 {
363                                         softwaretransform(v, skyvert[currentskyvert].v);
364                                         currentskyvert++;
365                                 }
366                         }
367                         else
368                         {
369                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
370                                 {
371                                         skyvert[currentskyvert].v[0] = v[0];
372                                         skyvert[currentskyvert].v[1] = v[1];
373                                         skyvert[currentskyvert++].v[2] = v[2];
374                                 }
375                         }
376                 }
377         }
378 }
379
380 void R_LightSurface(int *dlightbits, glpoly_t *polys, float *wvert)
381 {
382         float           cr, cg, cb, radius, radius2, f, *v, *wv;
383         int                     i, a, b;
384         unsigned int c;
385         dlight_t        *light;
386         vec_t           *lightorigin;
387         glpoly_t        *p;
388         for (a = 0;a < 8;a++)
389         {
390                 if ((c = dlightbits[a]))
391                 {
392                         for (b = 0;c && b < 32;b++)
393                         {
394                                 if (c & (1 << b))
395                                 {
396                                         c -= (1 << b);
397                                         light = &cl_dlights[a * 32 + b];
398                                         lightorigin = light->origin;
399                                         cr = light->color[0];
400                                         cg = light->color[1];
401                                         cb = light->color[2];
402                                         radius = light->radius*light->radius*16.0f;
403                                         radius2 = radius * 16.0f;
404                                         wv = wvert;
405                                         for (p = polys;p;p = p->next)
406                                         {
407                                                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
408                                                 {
409                                                         f = VectorDistance2(wv, lightorigin);
410                                                         if (f < radius)
411                                                         {
412                                                                 f = radius2 / (f + 65536.0f);
413                                                                 wv[3] += cr * f;
414                                                                 wv[4] += cg * f;
415                                                                 wv[5] += cb * f;
416                                                         }
417                                                         wv += 6;
418                                                 }
419                                         }
420                                 }
421                                 c >>= 1;
422                                 b++;
423                         }
424                 }
425         }
426 }
427
428 void R_WaterSurf(msurface_t *s, texture_t *t, qboolean transform, int alpha)
429 {
430         int             i;
431         float   os = turbsin[(int)(realtime * TURBSCALE) & 255], ot = turbsin[(int)(realtime * TURBSCALE + 96.0) & 255];
432         glpoly_t *p;
433         float   wvert[64*6], *wv, *v;
434         wv = wvert;
435         for (p = s->polys;p;p = p->next)
436         {
437                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
438                 {
439                         if (transform)
440                                 softwaretransform(v, wv);
441                         else
442                                 VectorCopy(v, wv);
443                         if (r_waterripple.value)
444                                 wv[2] += r_waterripple.value * turbsin[(int)((wv[0]*0.125f+realtime) * TURBSCALE) & 255] * turbsin[(int)((wv[1]*0.125f+realtime) * TURBSCALE) & 255] * (1.0f / 64.0f);
445                         wv[3] = wv[4] = wv[5] = 128.0f;
446                         wv += 6;
447                 }
448         }
449         if (s->dlightframe == r_dlightframecount && r_dynamic.value)
450                 R_LightSurface(s->dlightbits, s->polys, wvert);
451         wv = wvert;
452         // FIXME: make fog texture if water texture is transparent?
453         if (lighthalf)
454         {
455                 for (p=s->polys ; p ; p=p->next)
456                 {
457                         transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, TPOLYTYPE_ALPHA);
458                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
459                                 transpolyvert(wv[0], wv[1], wv[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), (int) wv[3] >> 1,(int) wv[4] >> 1,(int) wv[5] >> 1,alpha);
460                         transpolyend();
461                 }
462         }
463         else
464         {
465                 for (p=s->polys ; p ; p=p->next)
466                 {
467                         transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, TPOLYTYPE_ALPHA);
468                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
469                                 transpolyvert(wv[0], wv[1], wv[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), (int) wv[3],(int) wv[4],(int) wv[5],alpha);
470                         transpolyend();
471                 }
472         }
473 }
474
475 void R_WallSurf(msurface_t *s, texture_t *t, qboolean transform)
476 {
477         int                     i;
478         glpoly_t        *p;
479         float           wvert[64*6], *wv, *v;
480         // check for lightmap modification
481         if (r_dynamic.value)
482         {
483                 if (r_ambient.value != s->cached_ambient || lighthalf != s->cached_lighthalf
484                 || (s->styles[0] != 255 && d_lightstylevalue[s->styles[0]] != s->cached_light[0])
485                 || (s->styles[1] != 255 && d_lightstylevalue[s->styles[1]] != s->cached_light[1])
486                 || (s->styles[2] != 255 && d_lightstylevalue[s->styles[2]] != s->cached_light[2])
487                 || (s->styles[3] != 255 && d_lightstylevalue[s->styles[3]] != s->cached_light[3]))
488                         R_UpdateLightmap(s, s->lightmaptexturenum);
489         }
490         wv = wvert;
491         for (p = s->polys;p;p = p->next)
492         {
493                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
494                 {
495                         if (transform)
496                                 softwaretransform(v, wv);
497                         else
498                                 VectorCopy(v, wv);
499                         wv[3] = wv[4] = wv[5] = 0.0f;
500                         wv += 6;
501                 }
502         }
503         if (s->dlightframe == r_dlightframecount && r_dynamic.value)
504                 R_LightSurface(s->dlightbits, s->polys, wvert);
505         wv = wvert;
506         for (p = s->polys;p;p = p->next)
507         {
508                 if (currentwallpoly >= MAX_WALLPOLYS)
509                         break;
510                 v = p->verts[0];
511                 wallpoly[currentwallpoly].texnum = (unsigned short) t->gl_texturenum;
512                 wallpoly[currentwallpoly].lighttexnum = (unsigned short) lightmap_textures + s->lightmaptexturenum;
513                 wallpoly[currentwallpoly].glowtexnum = (unsigned short) t->gl_glowtexturenum;
514                 wallpoly[currentwallpoly].firstvert = currentwallvert;
515                 wallpoly[currentwallpoly].numverts = p->numverts;
516                 wallpoly[currentwallpoly++].lit = true;
517                 for (i = 0;i<p->numverts;i++, v += VERTEXSIZE)
518                 {
519                         if (lighthalf)
520                         {
521                                 wallvert[currentwallvert].r = (byte) (bound(0, (int) wv[3] >> 1, 255));
522                                 wallvert[currentwallvert].g = (byte) (bound(0, (int) wv[4] >> 1, 255));
523                                 wallvert[currentwallvert].b = (byte) (bound(0, (int) wv[5] >> 1, 255));
524                                 wallvert[currentwallvert].a = 255;
525                         }
526                         else
527                         {
528                                 wallvert[currentwallvert].r = (byte) (bound(0, (int) wv[3], 255));
529                                 wallvert[currentwallvert].g = (byte) (bound(0, (int) wv[4], 255));
530                                 wallvert[currentwallvert].b = (byte) (bound(0, (int) wv[5], 255));
531                                 wallvert[currentwallvert].a = 255;
532                         }
533                         wallvert[currentwallvert].vert[0] = wv[0];
534                         wallvert[currentwallvert].vert[1] = wv[1];
535                         wallvert[currentwallvert].vert[2] = wv[2];
536                         wallvert[currentwallvert].s = v[3];
537                         wallvert[currentwallvert].t = v[4];
538                         wallvert[currentwallvert].u = v[5];
539                         wallvert[currentwallvert++].v = v[6];
540                         wv += 6;
541                 }
542         }
543 }
544
545 // LordHavoc: transparent brush models
546 extern int r_dlightframecount;
547 extern float modelalpha;
548 //extern vec3_t shadecolor;
549 //qboolean R_CullBox (vec3_t mins, vec3_t maxs);
550 //void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits);
551 //void R_DynamicLightPointNoMask(vec3_t color, vec3_t org);
552 //void EmitWaterPolys (msurface_t *fa);
553
554 void R_WallSurfVertex(msurface_t *s, texture_t *t, qboolean transform, qboolean isbmodel)
555 {
556         int                     i, alpha;
557         glpoly_t        *p;
558         float           wvert[64*6], *wv, *v;
559         int                     size3;
560         float           scale;
561         byte            *lm;
562         size3 = ((s->extents[0]>>4)+1)*((s->extents[1]>>4)+1)*3; // *3 for colored lighting
563         alpha = (int) (modelalpha * 255.0f);
564         // check for lightmap modification
565         if (r_dynamic.value)
566         {
567                 if (r_ambient.value != s->cached_ambient || lighthalf != s->cached_lighthalf
568                 || (s->styles[0] != 255 && d_lightstylevalue[s->styles[0]] != s->cached_light[0])
569                 || (s->styles[1] != 255 && d_lightstylevalue[s->styles[1]] != s->cached_light[1])
570                 || (s->styles[2] != 255 && d_lightstylevalue[s->styles[2]] != s->cached_light[2])
571                 || (s->styles[3] != 255 && d_lightstylevalue[s->styles[3]] != s->cached_light[3]))
572                         R_UpdateLightmap(s, s->lightmaptexturenum);
573         }
574         wv = wvert;
575         for (p = s->polys;p;p = p->next)
576         {
577                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
578                 {
579                         if (transform)
580                                 softwaretransform(v, wv);
581                         else
582                                 VectorCopy(v, wv);
583                         wv[3] = wv[4] = wv[5] = r_ambient.value * 2.0f;
584                         if (s->styles[0] != 255)
585                         {
586                                 lm = (byte *)((long) s->samples + (int) v[7]);
587                                 scale = d_lightstylevalue[s->styles[0]] * (1.0f / 128.0f);wv[3] += lm[size3*0+0] * scale;wv[4] += lm[size3*0+1] * scale;wv[5] += lm[size3*0+2] * scale;
588                                 if (s->styles[1] != 255)
589                                 {
590                                         scale = d_lightstylevalue[s->styles[1]] * (1.0f / 128.0f);wv[3] += lm[size3*1+0] * scale;wv[4] += lm[size3*1+1] * scale;wv[5] += lm[size3*1+2] * scale;
591                                         if (s->styles[2] != 255)
592                                         {
593                                                 scale = d_lightstylevalue[s->styles[2]] * (1.0f / 128.0f);wv[3] += lm[size3*2+0] * scale;wv[4] += lm[size3*2+1] * scale;wv[5] += lm[size3*2+2] * scale;
594                                                 if (s->styles[3] != 255)
595                                                 {
596                                                         scale = d_lightstylevalue[s->styles[3]] * (1.0f / 128.0f);wv[3] += lm[size3*3+0] * scale;wv[4] += lm[size3*3+1] * scale;wv[5] += lm[size3*3+2] * scale;
597                                                 }
598                                         }
599                                 }
600                         }
601                         wv += 6;
602                 }
603         }
604         if (s->dlightframe == r_dlightframecount && r_dynamic.value)
605                 R_LightSurface(s->dlightbits, s->polys, wvert);
606         wv = wvert;
607         if (isbmodel && (currententity->colormod[0] != 1 || currententity->colormod[1] != 1 || currententity->colormod[2] != 1))
608         {
609                 if (lighthalf)
610                 {
611                         for (p = s->polys;p;p = p->next)
612                         {
613                                 v = p->verts[0];
614                                 transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
615                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
616                                         transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], (int) (wv[3] * currententity->colormod[0]) >> 1,(int) (wv[4] * currententity->colormod[1]) >> 1,(int) (wv[5] * currententity->colormod[0]) >> 1,alpha);
617                                 transpolyend();
618                         }
619                 }
620                 else
621                 {
622                         for (p = s->polys;p;p = p->next)
623                         {
624                                 v = p->verts[0];
625                                 transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
626                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
627                                         transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], (int) (wv[3] * currententity->colormod[0]),(int) (wv[4] * currententity->colormod[1]),(int) (wv[5] * currententity->colormod[2]),alpha);
628                                 transpolyend();
629                         }
630                 }
631         }
632         else
633         {
634                 if (lighthalf)
635                 {
636                         for (p = s->polys;p;p = p->next)
637                         {
638                                 v = p->verts[0];
639                                 transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
640                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
641                                         transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], (int) wv[3] >> 1,(int) wv[4] >> 1,(int) wv[5] >> 1,alpha);
642                                 transpolyend();
643                         }
644                 }
645                 else
646                 {
647                         for (p = s->polys;p;p = p->next)
648                         {
649                                 v = p->verts[0];
650                                 transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
651                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
652                                         transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], (int) wv[3],(int) wv[4],(int) wv[5],alpha);
653                                 transpolyend();
654                         }
655                 }
656         }
657 }
658
659 /*
660 ================
661 DrawTextureChains
662 ================
663 */
664 extern qboolean hlbsp;
665 extern char skyname[];
666 //extern qboolean SV_TestLine (hull_t *hull, int num, vec3_t p1, vec3_t p2);
667 void DrawTextureChains (void)
668 {
669         int                     n;
670         msurface_t      *s;
671         texture_t       *t;
672
673         for (n = 0;n < cl.worldmodel->numtextures;n++)
674         {
675                 if (!cl.worldmodel->textures[n] || !(s = cl.worldmodel->textures[n]->texturechain))
676                         continue;
677                 // LordHavoc: decide the render type only once, because the surface properties were determined by texture anyway
678                 cl.worldmodel->textures[n]->texturechain = NULL;
679                 t = R_TextureAnimation (cl.worldmodel->textures[n]);
680                 // sky
681                 if (s->flags & SURF_DRAWSKY)
682                 {
683                         skyisvisible = true;
684                         if (!hlbsp) // LordHavoc: HalfLife maps have freaky skypolys...
685                                 for (;s;s = s->texturechain)
686                                         R_SkySurf(s, false);
687                         continue;
688                 }
689                 // subdivided water surface warp
690                 if (s->flags & SURF_DRAWTURB)
691                 {
692                         int alpha = s->flags & SURF_DRAWNOALPHA ? 255 : r_wateralpha.value*255.0f;
693                         for (;s;s = s->texturechain)
694                                 R_WaterSurf(s, t, false, alpha);
695                         continue;
696                 }
697                 if (gl_vertex.value)
698                         for (;s;s = s->texturechain)
699                                 R_WallSurfVertex(s, t, false, false);
700                 else
701                         for (;s;s = s->texturechain)
702                                 R_WallSurf(s, t, false);
703         }
704 }
705
706 void R_NoVisMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, model_t *model);
707
708 /*
709 =================
710 R_DrawBrushModel
711 =================
712 */
713 void R_DrawBrushModel (entity_t *e)
714 {
715         int                     i;
716         vec3_t          mins, maxs;
717         msurface_t      *s;
718         model_t         *clmodel;
719         qboolean        rotated, vertexlit = false;
720         texture_t       *t;
721         vec3_t          org;
722
723         currententity = e;
724
725         clmodel = e->model;
726
727         if (e->angles[0] || e->angles[1] || e->angles[2])
728         {
729                 rotated = true;
730                 for (i=0 ; i<3 ; i++)
731                 {
732                         mins[i] = e->origin[i] - clmodel->radius;
733                         maxs[i] = e->origin[i] + clmodel->radius;
734                 }
735         }
736         else
737         {
738                 rotated = false;
739                 VectorAdd (e->origin, clmodel->mins, mins);
740                 VectorAdd (e->origin, clmodel->maxs, maxs);
741         }
742
743         if (R_CullBox (mins, maxs))
744                 return;
745
746         VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
747         if (rotated)
748         {
749                 vec3_t  temp;
750                 vec3_t  forward, right, up;
751
752                 VectorCopy (modelorg, temp);
753                 AngleVectors (e->angles, forward, right, up);
754                 modelorg[0] = DotProduct (temp, forward);
755                 modelorg[1] = -DotProduct (temp, right);
756                 modelorg[2] = DotProduct (temp, up);
757         }
758
759         s = &clmodel->surfaces[clmodel->firstmodelsurface];
760
761 // calculate dynamic lighting for bmodel if it's not an
762 // instanced model
763         for (i = 0;i < MAX_DLIGHTS;i++)
764         {
765                 if ((cl_dlights[i].die < cl.time) || (!cl_dlights[i].radius))
766                         continue;
767
768                 VectorSubtract(cl_dlights[i].origin, currententity->origin, org);
769                 R_NoVisMarkLights (org, &cl_dlights[i], 1<<(i&31), i >> 5, clmodel);
770         }
771         vertexlit = modelalpha != 1 || clmodel->firstmodelsurface == 0 || (currententity->effects & EF_FULLBRIGHT) || currententity->colormod[0] != 1 || currententity->colormod[2] != 1 || currententity->colormod[2] != 1;
772
773 e->angles[0] = -e->angles[0];   // stupid quake bug
774         softwaretransformforentity (e);
775 e->angles[0] = -e->angles[0];   // stupid quake bug
776
777         // draw texture
778         for (i = 0;i < clmodel->nummodelsurfaces;i++, s++)
779         {
780                 if (((s->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, s->plane) >= 0))
781                 {
782                         if (s->flags & SURF_DRAWSKY)
783                         {
784                                 R_SkySurf(s, true);
785                                 continue;
786                         }
787                         t = R_TextureAnimation (s->texinfo->texture);
788                         if (s->flags & SURF_DRAWTURB)
789                         {
790                                 R_WaterSurf(s, t, true, s->flags & SURF_DRAWNOALPHA ? 255 : r_wateralpha.value*255.0f);
791                                 continue;
792                         }
793                         if (vertexlit || s->texinfo->texture->transparent)
794                                 R_WallSurfVertex(s, t, true, true);
795                         else
796                                 R_WallSurf(s, t, true);
797                 }
798         }
799         UploadLightmaps();
800 }
801
802 /*
803 =============================================================
804
805         WORLD MODEL
806
807 =============================================================
808 */
809
810 void R_StoreEfrags (efrag_t **ppefrag);
811
812 /*
813 ================
814 R_WorldNode
815 ================
816 */
817 void R_WorldNode ()
818 {
819         int             c, side, s = 0;
820         double  dot;
821         struct
822         {
823                 double dot;
824                 mnode_t *node;
825         } nodestack[8192];
826         mnode_t *node;
827
828         if (!(node = cl.worldmodel->nodes))
829                 return;
830
831         while(1)
832         {
833         // if a leaf node, draw stuff
834                 if (node->contents < 0)
835                 {
836                         if (node->contents != CONTENTS_SOLID)
837                         {
838                                 mleaf_t         *pleaf;
839                                 pleaf = (mleaf_t *)node;
840
841                                 c_leafs++;
842                                 if ((c = pleaf->nummarksurfaces))
843                                 {
844                                         msurface_t      **mark;
845                                         mark = pleaf->firstmarksurface;
846                                         do
847                                         {
848                                                 (*mark)->visframe = r_framecount;
849                                                 mark++;
850                                         } while (--c);
851                                 }
852
853                                 // deal with model fragments in this leaf
854                                 if (pleaf->efrags)
855                                         R_StoreEfrags (&pleaf->efrags);
856                         }
857
858                         if (!s)
859                                 break;
860                         node = nodestack[--s].node;
861                         dot = nodestack[s].dot;
862                         goto loc0;
863                 }
864
865                 c_nodes++;
866
867         // node is just a decision point, so go down the apropriate sides
868
869         // find which side of the node we are on
870                 dot = (node->plane->type < 3 ? modelorg[node->plane->type] : DotProduct (modelorg, node->plane->normal)) - node->plane->dist;
871
872         // recurse down the children, front side first
873                 side = dot < 0;
874                 if (node->children[side]->visframe == r_visframecount && R_NotCulledBox(node->children[side]->minmaxs, node->children[side]->minmaxs+3))
875                 {
876                         nodestack[s].node = node;
877                         nodestack[s++].dot = dot;
878                         node = node->children[side];
879                         continue;
880                 }
881 loc0:
882
883                 // backside
884                 side = dot >= 0;
885         // draw stuff
886                 if ((c = node->numsurfaces))
887                 {
888                         msurface_t      *surf;
889                         surf = cl.worldmodel->surfaces + node->firstsurface;
890
891                         if (side)
892                         {
893                                 for (;c;c--, surf++)
894                                 {
895                                         if (surf->visframe == r_framecount && !(surf->flags & SURF_PLANEBACK))
896                                         {
897                                                 surf->texturechain = surf->texinfo->texture->texturechain;
898                                                 surf->texinfo->texture->texturechain = surf;
899                                         }
900                                 }
901                         }
902                         else
903                         {
904                                 for (;c;c--, surf++)
905                                 {
906                                         if (surf->visframe == r_framecount && (surf->flags & SURF_PLANEBACK))
907                                         {
908                                                 surf->texturechain = surf->texinfo->texture->texturechain;
909                                                 surf->texinfo->texture->texturechain = surf;
910                                         }
911                                 }
912                         }
913                 }
914
915         // recurse down the back side
916                 if (node->children[side]->visframe == r_visframecount && R_NotCulledBox(node->children[side]->minmaxs, node->children[side]->minmaxs+3))
917                 {
918                         node = node->children[side];
919                         continue;
920                 }
921
922                 if (!s)
923                         break;
924                 node = nodestack[--s].node;
925                 dot = nodestack[s].dot;
926                 goto loc0;
927         }
928 }
929
930
931 /*
932 =============
933 R_DrawWorld
934 =============
935 */
936 void R_DrawWorld (void)
937 {
938         entity_t        ent;
939
940         memset (&ent, 0, sizeof(ent));
941         ent.model = cl.worldmodel;
942         ent.colormod[0] = ent.colormod[1] = ent.colormod[2] = 1;
943         modelalpha = ent.alpha = 1;
944         ent.scale = 1;
945
946         VectorCopy (r_refdef.vieworg, modelorg);
947
948         currententity = &ent;
949
950         softwaretransformidentity(); // LordHavoc: clear transform
951
952         if (cl.worldmodel)
953                 R_WorldNode ();
954
955         glClear (GL_DEPTH_BUFFER_BIT);
956
957         R_PushDlights (); // now mark the lit surfaces
958
959         DrawTextureChains ();
960
961         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
962         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
963 }
964
965
966 /*
967 ===============
968 R_MarkLeaves
969 ===============
970 */
971 void R_MarkLeaves (void)
972 {
973         byte    *vis;
974         mnode_t *node;
975         int             i;
976
977         if (r_oldviewleaf == r_viewleaf && !r_novis.value)
978                 return;
979         
980         r_visframecount++;
981         r_oldviewleaf = r_viewleaf;
982
983         if (r_novis.value)
984         {
985                 for (i=0 ; i<cl.worldmodel->numleafs ; i++)
986                 {
987                         node = (mnode_t *)&cl.worldmodel->leafs[i+1];
988                         do
989                         {
990                                 if (node->visframe == r_visframecount)
991                                         break;
992                                 node->visframe = r_visframecount;
993                                 node = node->parent;
994                         } while (node);
995                 }
996         }
997         else
998         {
999                 vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
1000                 
1001                 for (i=0 ; i<cl.worldmodel->numleafs ; i++)
1002                 {
1003                         if (vis[i>>3] & (1<<(i&7)))
1004                         {
1005                                 node = (mnode_t *)&cl.worldmodel->leafs[i+1];
1006                                 do
1007                                 {
1008                                         if (node->visframe == r_visframecount)
1009                                                 break;
1010                                         node->visframe = r_visframecount;
1011                                         node = node->parent;
1012                                 } while (node);
1013                         }
1014                 }
1015         }
1016 }
1017
1018
1019
1020 /*
1021 =============================================================================
1022
1023   LIGHTMAP ALLOCATION
1024
1025 =============================================================================
1026 */
1027
1028 // returns a texture number and the position inside it
1029 int AllocBlock (int w, int h, int *x, int *y)
1030 {
1031         int             i, j;
1032         int             best, best2;
1033         int             texnum;
1034
1035         for (texnum=0 ; texnum<MAX_LIGHTMAPS ; texnum++)
1036         {
1037                 best = BLOCK_HEIGHT;
1038
1039                 for (i=0 ; i<BLOCK_WIDTH-w ; i+=lightmapalign) // LordHavoc: NVIDIA has broken subimage, so align the lightmaps
1040                 {
1041                         best2 = 0;
1042
1043                         for (j=0 ; j<w ; j++)
1044                         {
1045                                 if (allocated[texnum][i+j] >= best)
1046                                         break;
1047                                 if (allocated[texnum][i+j] > best2)
1048                                         best2 = allocated[texnum][i+j];
1049                         }
1050                         if (j == w)
1051                         {       // this is a valid spot
1052                                 *x = i;
1053                                 *y = best = best2;
1054                         }
1055                 }
1056
1057                 if (best + h > BLOCK_HEIGHT)
1058                         continue;
1059
1060                 if (nosubimagefragments || nosubimage)
1061                 {
1062                         if (!lightmaps[texnum])
1063                                 lightmaps[texnum] = calloc(BLOCK_WIDTH*BLOCK_HEIGHT*4, 1);
1064                 }
1065                 // LordHavoc: clear texture to blank image, fragments are uploaded using subimage
1066                 else if (!allocated[texnum][0])
1067                 {
1068                         byte blank[BLOCK_WIDTH*BLOCK_HEIGHT*3];
1069                         memset(blank, 0, sizeof(blank));
1070                         glBindTexture(GL_TEXTURE_2D, lightmap_textures + texnum);
1071                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1072                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1073                         if (lightmaprgba)
1074                                 glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank);
1075                         else
1076                                 glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, blank);
1077                 }
1078
1079                 for (i=0 ; i<w ; i++)
1080                         allocated[texnum][*x + i] = best + h;
1081
1082                 return texnum;
1083         }
1084
1085         Sys_Error ("AllocBlock: full");
1086         return 0;
1087 }
1088
1089
1090 mvertex_t       *r_pcurrentvertbase;
1091 model_t         *currentmodel;
1092
1093 int     nColinElim;
1094
1095 /*
1096 ================
1097 BuildSurfaceDisplayList
1098 ================
1099 */
1100 void BuildSurfaceDisplayList (msurface_t *fa)
1101 {
1102         int                     i, j, lindex, lnumverts;
1103         medge_t         *pedges, *r_pedge;
1104         int                     vertpage;
1105         float           *vec;
1106         float           s, t;
1107         glpoly_t        *poly;
1108
1109 // reconstruct the polygon
1110         pedges = currentmodel->edges;
1111         lnumverts = fa->numedges;
1112         vertpage = 0;
1113
1114         //
1115         // draw texture
1116         //
1117         poly = Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float));
1118         poly->next = fa->polys;
1119         poly->flags = fa->flags;
1120         fa->polys = poly;
1121         poly->numverts = lnumverts;
1122
1123         for (i=0 ; i<lnumverts ; i++)
1124         {
1125                 lindex = currentmodel->surfedges[fa->firstedge + i];
1126
1127                 if (lindex > 0)
1128                 {
1129                         r_pedge = &pedges[lindex];
1130                         vec = r_pcurrentvertbase[r_pedge->v[0]].position;
1131                 }
1132                 else
1133                 {
1134                         r_pedge = &pedges[-lindex];
1135                         vec = r_pcurrentvertbase[r_pedge->v[1]].position;
1136                 }
1137                 s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
1138                 t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
1139
1140                 VectorCopy (vec, poly->verts[i]);
1141                 poly->verts[i][3] = s / fa->texinfo->texture->width;
1142                 poly->verts[i][4] = t / fa->texinfo->texture->height;
1143
1144                 //
1145                 // lightmap texture coordinates
1146                 //
1147                 s -= fa->texturemins[0];
1148                 t -= fa->texturemins[1];
1149                 s += 8;
1150                 t += 8;
1151                 // LordHavoc: calc lightmap data offset
1152                 j = (bound(0l, (int)t>>4, fa->extents[1]>>4) * ((fa->extents[0]>>4)+1) + bound(0l, (int)s>>4, fa->extents[0]>>4)) * 3;
1153                 poly->verts[i][7] = j;
1154                 s += fa->light_s*16;
1155                 s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
1156
1157                 t += fa->light_t*16;
1158                 t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
1159
1160                 poly->verts[i][5] = s;
1161                 poly->verts[i][6] = t;
1162         }
1163
1164         //
1165         // remove co-linear points - Ed
1166         //
1167         /*
1168         if (!gl_keeptjunctions.value)
1169         {
1170                 for (i = 0 ; i < lnumverts ; ++i)
1171                 {
1172                         vec3_t v1, v2;
1173                         float *prev, *this, *next;
1174
1175                         prev = poly->verts[(i + lnumverts - 1) % lnumverts];
1176                         this = poly->verts[i];
1177                         next = poly->verts[(i + 1) % lnumverts];
1178
1179                         VectorSubtract( this, prev, v1 );
1180                         VectorNormalize( v1 );
1181                         VectorSubtract( next, prev, v2 );
1182                         VectorNormalize( v2 );
1183
1184                         // skip co-linear points
1185                         #define COLINEAR_EPSILON 0.001
1186                         if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
1187                                 (fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) && 
1188                                 (fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
1189                         {
1190                                 int j;
1191                                 for (j = i + 1; j < lnumverts; ++j)
1192                                 {
1193                                         int k;
1194                                         for (k = 0; k < VERTEXSIZE; ++k)
1195                                                 poly->verts[j - 1][k] = poly->verts[j][k];
1196                                 }
1197                                 --lnumverts;
1198                                 ++nColinElim;
1199                                 // retry next vertex next time, which is now current vertex
1200                                 --i;
1201                         }
1202                 }
1203         }
1204         */
1205         poly->numverts = lnumverts;
1206 }
1207
1208 /*
1209 ========================
1210 GL_CreateSurfaceLightmap
1211 ========================
1212 */
1213 void GL_CreateSurfaceLightmap (msurface_t *surf)
1214 {
1215         int             smax, tmax;
1216
1217         if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
1218                 return;
1219
1220         smax = (surf->extents[0]>>4)+1;
1221         tmax = (surf->extents[1]>>4)+1;
1222
1223         surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
1224         if (nosubimage || nosubimagefragments)
1225                 return;
1226         glBindTexture(GL_TEXTURE_2D, lightmap_textures + surf->lightmaptexturenum);
1227         smax = ((surf->extents[0]>>4)+lightmapalign) & lightmapalignmask;
1228         if (lightmaprgba)
1229         {
1230                 R_BuildLightMap (surf, templight, smax * 4);
1231                 glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
1232         }
1233         else
1234         {
1235                 R_BuildLightMap (surf, templight, smax * 3);
1236                 glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
1237         }
1238 }
1239
1240
1241 /*
1242 ==================
1243 GL_BuildLightmaps
1244
1245 Builds the lightmap texture
1246 with all the surfaces from all brush models
1247 ==================
1248 */
1249 void GL_BuildLightmaps (void)
1250 {
1251         int             i, j;
1252         model_t *m;
1253
1254         memset (allocated, 0, sizeof(allocated));
1255
1256         r_framecount = 1;               // no dlightcache
1257
1258         if (gl_nosubimagefragments.value)
1259                 nosubimagefragments = 1;
1260         else
1261                 nosubimagefragments = 0;
1262
1263         if (gl_nosubimage.value)
1264                 nosubimage = 1;
1265         else
1266                 nosubimage = 0;
1267
1268         if (gl_lightmaprgba.value)
1269         {
1270                 lightmaprgba = true;
1271                 lightmapbytes = 4;
1272         }
1273         else
1274         {
1275                 lightmaprgba = false;
1276                 lightmapbytes = 3;
1277         }
1278
1279         // LordHavoc: NVIDIA seems to have a broken glTexSubImage2D,
1280         //            it needs to be aligned on 4 pixel boundaries...
1281         //            so I implemented an adjustable lightmap alignment
1282         if (gl_lightmapalign.value < 1)
1283                 gl_lightmapalign.value = 1;
1284         if (gl_lightmapalign.value > 16)
1285                 gl_lightmapalign.value = 16;
1286         lightmapalign = 1;
1287         while (lightmapalign < gl_lightmapalign.value)
1288                 lightmapalign <<= 1;
1289         gl_lightmapalign.value = lightmapalign;
1290         lightmapalignmask = ~(lightmapalign - 1);
1291         if (nosubimagefragments || nosubimage)
1292         {
1293                 lightmapalign = 1;
1294                 lightmapalignmask = ~0;
1295         }
1296
1297         if (!lightmap_textures)
1298         {
1299                 lightmap_textures = texture_extension_number;
1300                 texture_extension_number += MAX_LIGHTMAPS;
1301         }
1302
1303         for (j=1 ; j<MAX_MODELS ; j++)
1304         {
1305                 m = cl.model_precache[j];
1306                 if (!m)
1307                         break;
1308                 if (m->name[0] == '*')
1309                         continue;
1310                 r_pcurrentvertbase = m->vertexes;
1311                 currentmodel = m;
1312                 for (i=0 ; i<m->numsurfaces ; i++)
1313                 {
1314                         if ( m->surfaces[i].flags & SURF_DRAWTURB )
1315                                 continue;
1316                         if ( m->surfaces[i].flags & SURF_DRAWSKY )
1317                                 continue;
1318                         GL_CreateSurfaceLightmap (m->surfaces + i);
1319                         BuildSurfaceDisplayList (m->surfaces + i);
1320                 }
1321         }
1322
1323         if (nosubimage || nosubimagefragments)
1324         {
1325                 if (gl_mtexable)
1326                         qglSelectTexture(gl_mtex_enum+1);
1327                 for (i = 0;i < MAX_LIGHTMAPS;i++)
1328                 {
1329                         if (!allocated[i][0])
1330                                 break;
1331                         lightmapupdate[i][0] = BLOCK_HEIGHT;
1332                         lightmapupdate[i][1] = 0;
1333                         glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
1334                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1335                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1336                         if (lightmaprgba)
1337                                 glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
1338                         else
1339                                 glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
1340                 }
1341                 if (gl_mtexable)
1342                         qglSelectTexture(gl_mtex_enum+0);
1343         }
1344 }
1345