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