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