]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rsurf.c
added CVAR_SAVE and CVAR_NOTIFY flags to cvar_t structure (at the beginning), updated...
[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 #define BLOCK_WIDTH             256
27 #define BLOCK_HEIGHT    256
28 // LordHavoc: increased lightmap limit from 64 to 1024
29 #define MAX_LIGHTMAPS   1024
30 #define LIGHTMAPSIZE    (BLOCK_WIDTH*BLOCK_HEIGHT*4)
31
32 int                     active_lightmaps;
33
34 short allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
35
36 byte *lightmaps[MAX_LIGHTMAPS];
37 short lightmapupdate[MAX_LIGHTMAPS][2];
38
39 signed int blocklights[BLOCK_WIDTH*BLOCK_HEIGHT*3]; // LordHavoc: *3 for colored lighting
40
41 int lightmapalign, lightmapalignmask; // LordHavoc: NVIDIA's broken subimage fix, see BuildLightmaps for notes
42 cvar_t gl_lightmapalign = {0, "gl_lightmapalign", "4"};
43 cvar_t gl_lightmaprgba = {0, "gl_lightmaprgba", "1"};
44 cvar_t gl_nosubimagefragments = {0, "gl_nosubimagefragments", "0"};
45 cvar_t gl_nosubimage = {0, "gl_nosubimage", "0"};
46 cvar_t r_ambient = {0, "r_ambient", "0"};
47 cvar_t gl_vertex = {0, "gl_vertex", "0"};
48 cvar_t r_dlightmap = {CVAR_SAVE, "r_dlightmap", "1"};
49 cvar_t r_drawportals = {0, "r_drawportals", "0"};
50 cvar_t r_testvis = {0, "r_testvis", "0"};
51 cvar_t r_solidworldnode = {0, "r_solidworldnode", "1"};
52
53 qboolean lightmaprgba, nosubimagefragments, nosubimage;
54 int lightmapbytes;
55
56 int wateralpha;
57
58 void gl_surf_start(void)
59 {
60 }
61
62 void gl_surf_shutdown(void)
63 {
64 }
65
66 void gl_surf_newmap(void)
67 {
68 }
69
70 void GL_Surf_Init(void)
71 {
72         int i;
73         for (i = 0;i < MAX_LIGHTMAPS;i++)
74                 lightmaps[i] = NULL;
75         Cvar_RegisterVariable(&gl_lightmapalign);
76         Cvar_RegisterVariable(&gl_lightmaprgba);
77         Cvar_RegisterVariable(&gl_nosubimagefragments);
78         Cvar_RegisterVariable(&gl_nosubimage);
79         Cvar_RegisterVariable(&r_ambient);
80         Cvar_RegisterVariable(&gl_vertex);
81         Cvar_RegisterVariable(&r_dlightmap);
82         Cvar_RegisterVariable(&r_drawportals);
83         Cvar_RegisterVariable(&r_testvis);
84         Cvar_RegisterVariable(&r_solidworldnode);
85
86         R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
87 }
88
89 int dlightdivtable[32768];
90
91 /*
92         R_AddDynamicLights
93 */
94 int R_AddDynamicLights (msurface_t *surf)
95 {
96         int         sdtable[18], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, red, green, blue, lit, dist2, impacts, impactt;
97         unsigned int *bl;
98         float       dist;
99         vec3_t      impact, local;
100
101         // LordHavoc: use 64bit integer...  shame it's not very standardized...
102 #if _MSC_VER || __BORLANDC__
103         __int64     k;
104 #else
105         long long   k;
106 #endif
107
108         lit = false;
109
110         if (!dlightdivtable[1])
111         {
112                 dlightdivtable[0] = 4194304;
113                 for (s = 1; s < 32768; s++)
114                         dlightdivtable[s] = 4194304 / (s << 7);
115         }
116
117         smax = (surf->extents[0] >> 4) + 1;
118         tmax = (surf->extents[1] >> 4) + 1;
119
120         for (lnum = 0; lnum < MAX_DLIGHTS; lnum++)
121         {
122                 if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
123                         continue;                                       // not lit by this light
124
125                 VectorSubtract (cl_dlights[lnum].origin, currententity->render.origin, local);
126                 dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
127
128                 // for comparisons to minimum acceptable light
129                 maxdist = (int) ((cl_dlights[lnum].radius * cl_dlights[lnum].radius));
130
131                 // clamp radius to avoid exceeding 32768 entry division table
132                 if (maxdist > 4194304)
133                         maxdist = 4194304;
134
135                 dist2 = dist * dist;
136                 if (dist2 >= maxdist)
137                         continue;
138
139                 impact[0] = cl_dlights[lnum].origin[0] - surf->plane->normal[0] * dist;
140                 impact[1] = cl_dlights[lnum].origin[1] - surf->plane->normal[1] * dist;
141                 impact[2] = cl_dlights[lnum].origin[2] - surf->plane->normal[2] * dist;
142
143                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
144                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
145
146                 s = bound(0, impacts, smax * 16) - impacts;
147                 t = bound(0, impactt, tmax * 16) - impactt;
148                 i = s * s + t * t + dist2;
149                 if (i > maxdist)
150                         continue;
151
152                 // reduce calculations
153                 for (s = 0, i = impacts; s < smax; s++, i -= 16)
154                         sdtable[s] = i * i + dist2 + LIGHTOFFSET;
155
156                 maxdist3 = maxdist - (int) (dist * dist);
157
158                 // convert to 8.8 blocklights format and scale up by radius
159                 red = cl_dlights[lnum].color[0] * maxdist;
160                 green = cl_dlights[lnum].color[1] * maxdist;
161                 blue = cl_dlights[lnum].color[2] * maxdist;
162                 bl = blocklights;
163
164                 i = impactt;
165                 for (t = 0; t < tmax; t++, i -= 16)
166                 {
167                         td = i * i;
168                         // make sure some part of it is visible on this line
169                         if (td < maxdist3)
170                         {
171                                 maxdist2 = maxdist - td;
172                                 for (s = 0; s < smax; s++)
173                                 {
174                                         if (sdtable[s] < maxdist2)
175                                         {
176                                                 k = dlightdivtable[(sdtable[s] + td) >> 7];
177                                                 bl[0] += (red   * k) >> 9;
178                                                 bl[1] += (green * k) >> 9;
179                                                 bl[2] += (blue  * k) >> 9;
180                                                 lit = true;
181                                         }
182                                         bl += 3;
183                                 }
184                         }
185                         else // skip line
186                                 bl += smax * 3;
187                 }
188         }
189         return lit;
190 }
191
192
193 void R_ConvertLightmap (int *in, byte *out, int width, int height, int stride)
194 {
195         int i, j;
196         stride -= (width*lightmapbytes);
197         if (lighthalf)
198         {
199                 // LordHavoc: I shift down by 8 unlike GLQuake's 7,
200                 // the image is brightened as a processing pass
201                 if (lightmaprgba)
202                 {
203                         for (i = 0;i < height;i++, out += stride)
204                         {
205                                 for (j = 0;j < width;j++, in += 3, out += 4)
206                                 {
207                                         out[0] = min(in[0] >> 8, 255);
208                                         out[1] = min(in[1] >> 8, 255);
209                                         out[2] = min(in[2] >> 8, 255);
210                                         out[3] = 255;
211                                 }
212                         }
213                 }
214                 else
215                 {
216                         for (i = 0;i < height;i++, out += stride)
217                         {
218                                 for (j = 0;j < width;j++, in += 3, out += 3)
219                                 {
220                                         out[0] = min(in[0] >> 8, 255);
221                                         out[1] = min(in[1] >> 8, 255);
222                                         out[2] = min(in[2] >> 8, 255);
223                                 }
224                         }
225                 }
226         }
227         else
228         {
229                 if (lightmaprgba)
230                 {
231                         for (i = 0;i < height;i++, out += stride)
232                         {
233                                 for (j = 0;j < width;j++, in += 3, out += 4)
234                                 {
235                                         out[0] = min(in[0] >> 7, 255);
236                                         out[1] = min(in[1] >> 7, 255);
237                                         out[2] = min(in[2] >> 7, 255);
238                                         out[3] = 255;
239                                 }
240                         }
241                 }
242                 else
243                 {
244                         for (i = 0;i < height;i++, out += stride)
245                         {
246                                 for (j = 0;j < width;j++, in += 3, out += 3)
247                                 {
248                                         out[0] = min(in[0] >> 7, 255);
249                                         out[1] = min(in[1] >> 7, 255);
250                                         out[2] = min(in[2] >> 7, 255);
251                                 }
252                         }
253                 }
254         }
255 }
256
257 /*
258 ===============
259 R_BuildLightMap
260
261 Combine and scale multiple lightmaps into the 8.8 format in blocklights
262 ===============
263 */
264 void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
265 {
266         int             smax, tmax;
267         int             i, j, size, size3;
268         byte    *lightmap;
269         int             scale;
270         int             maps;
271         int             *bl;
272
273         surf->cached_dlight = 0;
274         surf->cached_lighthalf = lighthalf;
275         surf->cached_ambient = r_ambient.value;
276
277         smax = (surf->extents[0]>>4)+1;
278         tmax = (surf->extents[1]>>4)+1;
279         size = smax*tmax;
280         size3 = size*3;
281         lightmap = surf->samples;
282
283 // set to full bright if no light data
284         if ((currententity && (currententity->render.effects & EF_FULLBRIGHT)) || !cl.worldmodel->lightdata)
285         {
286                 bl = blocklights;
287                 for (i=0 ; i<size ; i++)
288                 {
289                         *bl++ = 255*256;
290                         *bl++ = 255*256;
291                         *bl++ = 255*256;
292                 }
293         }
294         else
295         {
296 // clear to no light
297                 j = r_ambient.value * 512.0f; // would be 256.0f logically, but using 512.0f to match winquake style
298                 if (j)
299                 {
300                         bl = blocklights;
301                         for (i = 0;i < size3;i++)
302                                 *bl++ = j;
303                 }
304                 else
305                         memset(&blocklights[0], 0, size*3*sizeof(int));
306
307 // add all the lightmaps
308                 if (lightmap)
309                 {
310                         for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
311                         {
312                                 scale = d_lightstylevalue[surf->styles[maps]];
313                                 surf->cached_light[maps] = scale;       // 8.8 fraction
314                                 bl = blocklights;
315                                 for (i = 0;i < size3;i++)
316                                         *bl++ += *lightmap++ * scale;
317                         }
318                 }
319                 if (r_dlightmap.value && surf->dlightframe == r_framecount)
320                         if ((surf->cached_dlight = R_AddDynamicLights(surf)))
321                                 c_light_polys++;
322         }
323         R_ConvertLightmap(blocklights, dest, smax, tmax, stride);
324 }
325
326 byte templight[BLOCK_WIDTH*BLOCK_HEIGHT*4];
327
328 void R_UpdateLightmap(msurface_t *s, int lnum)
329 {
330         int smax, tmax;
331         // upload the new lightmap texture fragment
332         if(r_upload.value)
333                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + lnum);
334         if (nosubimage || nosubimagefragments)
335         {
336                 if (lightmapupdate[lnum][0] > s->light_t)
337                         lightmapupdate[lnum][0] = s->light_t;
338                 if (lightmapupdate[lnum][1] < (s->light_t + ((s->extents[1]>>4)+1)))
339                         lightmapupdate[lnum][1] = (s->light_t + ((s->extents[1]>>4)+1));
340                 if (lightmaprgba)
341                         R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 4, BLOCK_WIDTH * 4);
342                 else
343                         R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 3, BLOCK_WIDTH * 3);
344         }
345         else
346         {
347                 smax = ((s->extents[0]>>4)+lightmapalign) & lightmapalignmask;
348                 tmax = (s->extents[1]>>4)+1;
349                 if (lightmaprgba)
350                 {
351                         R_BuildLightMap (s, templight, smax * 4);
352                         if(r_upload.value)
353                                 glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
354                 }
355                 else
356                 {
357                         R_BuildLightMap (s, templight, smax * 3);
358                         if(r_upload.value)
359                                 glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
360                 }
361         }
362 }
363
364
365 /*
366 ===============
367 R_TextureAnimation
368
369 Returns the proper texture for a given time and base texture
370 ===============
371 */
372 texture_t *R_TextureAnimation (texture_t *base)
373 {
374 //      texture_t *original;
375 //      int             relative;
376 //      int             count;
377
378         if (currententity->render.frame)
379         {
380                 if (base->alternate_anims)
381                         base = base->alternate_anims;
382         }
383         
384         if (!base->anim_total)
385                 return base;
386
387         return base->anim_frames[(int)(cl.time*5) % base->anim_total];
388
389         /*
390         original = base;
391
392         relative = (int)(cl.time*5) % base->anim_total;
393
394         count = 0;      
395         while (base->anim_min > relative || base->anim_max <= relative)
396         {
397                 base = base->anim_next;
398                 if (!base)
399                 {
400                         Con_Printf("R_TextureAnimation: broken cycle");
401                         return original;
402                 }
403                 if (++count > 100)
404                 {
405                         Con_Printf("R_TextureAnimation: infinite cycle");
406                         return original;
407                 }
408         }
409
410         return base;
411         */
412 }
413
414
415 /*
416 =============================================================
417
418         BRUSH MODELS
419
420 =============================================================
421 */
422
423
424 float   turbsin[256] =
425 {
426         #include "gl_warp_sin.h"
427 };
428 #define TURBSCALE (256.0 / (2 * M_PI))
429
430
431 void UploadLightmaps(void)
432 {
433         int i;
434         if (nosubimage || nosubimagefragments)
435         {
436                 for (i = 0;i < MAX_LIGHTMAPS;i++)
437                 {
438                         if (lightmapupdate[i][0] < lightmapupdate[i][1])
439                         {
440                                 if(r_upload.value)
441                                 {
442                                         glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
443                                         if (nosubimage)
444                                         {
445                                                 if (lightmaprgba)
446                                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
447                                                 else
448                                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
449                                         }
450                                         else
451                                         {
452                                                 if (lightmaprgba)
453                                                         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]));
454                                                 else
455                                                         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]));
456                                         }
457                                 }
458                         }
459                         lightmapupdate[i][0] = BLOCK_HEIGHT;
460                         lightmapupdate[i][1] = 0;
461                 }
462         }
463 }
464
465 float   wvert[1024*6]; // used by the following functions
466
467 void RSurf_DrawSky(msurface_t *s, int transform)
468 {
469         glpoly_t *p;
470         int i;
471         float *v;
472
473         // LordHavoc: HalfLife maps have freaky skypolys...
474         if (hlbsp)
475                 return;
476
477         for (p=s->polys ; p ; p=p->next)
478         {
479                 if (currentskypoly < MAX_SKYPOLYS && currentskyvert + p->numverts <= MAX_SKYVERTS)
480                 {
481                         skypoly[currentskypoly].firstvert = currentskyvert;
482                         skypoly[currentskypoly++].verts = p->numverts;
483                         if (transform)
484                         {
485                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
486                                 {
487                                         softwaretransform(v, skyvert[currentskyvert].v);
488                                         currentskyvert++;
489                                 }
490                         }
491                         else
492                         {
493                                 for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
494                                 {
495                                         VectorCopy(v, skyvert[currentskyvert].v);
496                                         currentskyvert++;
497                                 }
498                         }
499                 }
500         }
501 }
502
503 int RSurf_Light(int *dlightbits, glpoly_t *polys)
504 {
505         float           cr, cg, cb, radius, radius2, f, *v, *wv;
506         int                     i, a, b, lit = false;
507         unsigned int c, d;
508         dlight_t        *light;
509         vec_t           *lightorigin;
510         glpoly_t        *p;
511         for (a = 0;a < 8;a++)
512         {
513                 if ((c = dlightbits[a]))
514                 {
515                         for (b = 0, d = 1;c;b++, d <<= 1)
516                         {
517                                 if (c & d)
518                                 {
519                                         c -= d;
520                                         light = &cl_dlights[a * 32 + b];
521                                         lightorigin = light->origin;
522                                         cr = light->color[0];
523                                         cg = light->color[1];
524                                         cb = light->color[2];
525                                         radius = light->radius*light->radius;
526                                         radius2 = radius * 256.0f;
527                                         wv = wvert;
528                                         for (p = polys;p;p = p->next)
529                                         {
530                                                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
531                                                 {
532                                                         f = VectorDistance2(wv, lightorigin);
533                                                         if (f < radius)
534                                                         {
535                                                                 f = radius2 / (f + LIGHTOFFSET);
536                                                                 wv[3] += cr * f;
537                                                                 wv[4] += cg * f;
538                                                                 wv[5] += cb * f;
539                                                                 lit = true;
540                                                         }
541                                                         wv += 6;
542                                                 }
543                                         }
544                                 }
545                         }
546                 }
547         }
548         return lit;
549 }
550
551 void RSurf_DrawWater(msurface_t *s, texture_t *t, int transform, int alpha)
552 {
553         int             i;
554         float   os = turbsin[(int)(cl.time * TURBSCALE) & 255], ot = turbsin[(int)(cl.time * TURBSCALE + 96.0) & 255];
555         glpoly_t *p;
556         float   *v;
557         // FIXME: make fog texture if water texture is transparent?
558
559         if (s->dlightframe != r_framecount)
560         {
561                 vec3_t temp;
562                 // LordHavoc: fast path for no vertex lighting cases
563                 if (transform)
564                 {
565                         if (r_waterripple.value)
566                         {
567                                 for (p=s->polys ; p ; p=p->next)
568                                 {
569                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
570                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
571                                         {
572                                                 softwaretransform(v, temp);
573                                                 transpolyvert(temp[0], temp[1], temp[2] + r_waterripple.value * turbsin[(int)((temp[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((temp[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * (1.0f / 64.0f), (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
574                                         }
575                                         transpolyend();
576                                 }
577                         }
578                         else
579                         {
580                                 for (p=s->polys ; p ; p=p->next)
581                                 {
582                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
583                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
584                                         {
585                                                 softwaretransform(v, temp);
586                                                 transpolyvert(temp[0], temp[1], temp[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
587                                         }
588                                         transpolyend();
589                                 }
590                         }
591                 }
592                 else
593                 {
594                         if (r_waterripple.value)
595                         {
596                                 for (p=s->polys ; p ; p=p->next)
597                                 {
598                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
599                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
600                                                 transpolyvert(v[0], v[1], v[2] + r_waterripple.value * turbsin[(int)((v[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((v[1]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * (1.0f / 64.0f), (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
601                                         transpolyend();
602                                 }
603                         }
604                         else
605                         {
606                                 for (p=s->polys ; p ; p=p->next)
607                                 {
608                                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
609                                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
610                                                 transpolyvert(v[0], v[1], v[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), 128, 128, 128, alpha);
611                                         transpolyend();
612                                 }
613                         }
614                 }
615         }
616         else
617         {
618                 float *wv;
619                 wv = wvert;
620                 for (p = s->polys;p;p = p->next)
621                 {
622                         for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
623                         {
624                                 if (transform)
625                                         softwaretransform(v, wv);
626                                 else
627                                         VectorCopy(v, wv);
628                                 if (r_waterripple.value)
629                                         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)+cl.time) * TURBSCALE) & 255] * (1.0f / 64.0f);
630                                 wv[3] = wv[4] = wv[5] = 128.0f;
631                                 wv += 6;
632                         }
633                 }
634                 if (s->dlightframe == r_framecount)
635                         RSurf_Light(s->dlightbits, s->polys);
636                 wv = wvert;
637                 for (p=s->polys ; p ; p=p->next)
638                 {
639                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, TPOLYTYPE_ALPHA);
640                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
641                                 transpolyvert(wv[0], wv[1], wv[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), wv[3], wv[4], wv[5], alpha);
642                         transpolyend();
643                 }
644         }
645 }
646
647 void RSurf_DrawWall(msurface_t *s, texture_t *t, int transform)
648 {
649         int             i, lit = false, polys = 0, verts = 0;
650         float   *v;
651         glpoly_t *p;
652         wallpoly_t *wp;
653         wallvert_t *out;
654         wallvertcolor_t *outcolor;
655         // check for lightmap modification
656         if (s->cached_dlight
657          || (r_dynamic.value && r_dlightmap.value && s->dlightframe == r_framecount)
658          || r_ambient.value != s->cached_ambient
659          || lighthalf != s->cached_lighthalf
660          || (r_dynamic.value
661          && ((s->styles[0] != 255 && d_lightstylevalue[s->styles[0]] != s->cached_light[0])
662          || (s->styles[1] != 255 && d_lightstylevalue[s->styles[1]] != s->cached_light[1])
663          || (s->styles[2] != 255 && d_lightstylevalue[s->styles[2]] != s->cached_light[2])
664          || (s->styles[3] != 255 && d_lightstylevalue[s->styles[3]] != s->cached_light[3]))))
665                 R_UpdateLightmap(s, s->lightmaptexturenum);
666         if (s->dlightframe != r_framecount || r_dlightmap.value)
667         {
668                 // LordHavoc: fast path version for no vertex lighting cases
669                 wp = &wallpoly[currentwallpoly];
670                 out = &wallvert[currentwallvert];
671                 for (p = s->polys;p;p = p->next)
672                 {
673                         if ((currentwallpoly >= MAX_WALLPOLYS) || (currentwallvert+p->numverts > MAX_WALLVERTS))
674                                 return;
675                         wp->texnum = (unsigned short) R_GetTexture(t->texture);
676                         wp->lighttexnum = (unsigned short) (lightmap_textures + s->lightmaptexturenum);
677                         wp->glowtexnum = (unsigned short) R_GetTexture(t->glowtexture);
678                         wp->firstvert = currentwallvert;
679                         wp->numverts = p->numverts;
680                         wp->lit = false;
681                         wp++;
682                         currentwallpoly++;
683                         currentwallvert += p->numverts;
684                         v = p->verts[0];
685                         if (transform)
686                         {
687                                 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
688                                 {
689                                         softwaretransform(v, out->vert);
690                                         out->vert[3] = v[3];
691                                         out->vert[4] = v[4];
692                                         out->vert[5] = v[5];
693                                         out->vert[6] = v[6];
694                                 }
695                         }
696                         else
697                         {
698                                 /*
699                                 for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, out++)
700                                 {
701                                         VectorCopy(v, out->vert);
702                                         out->vert[3] = v[3];
703                                         out->vert[4] = v[4];
704                                         out->vert[5] = v[5];
705                                         out->vert[6] = v[6];
706                                 }
707                                 */
708                                 memcpy(out, v, sizeof(vec_t) * VERTEXSIZE * p->numverts);
709                                 out += p->numverts;
710                         }
711                 }
712         }
713         else
714         {
715                 float *wv;
716                 wv = wvert;
717                 for (p = s->polys;p;p = p->next)
718                 {
719                         for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
720                         {
721                                 if (transform)
722                                         softwaretransform(v, wv);
723                                 else
724                                         VectorCopy(v, wv);
725                                 wv[3] = wv[4] = wv[5] = 0.0f;
726                                 wv += 6;
727                         }
728                         verts += p->numverts;
729                         polys++;
730                 }
731                 if ((currentwallpoly + polys > MAX_WALLPOLYS) || (currentwallvert+verts > MAX_WALLVERTS))
732                         return;
733                 if ((!r_dlightmap.value) && s->dlightframe == r_framecount)
734                         lit = RSurf_Light(s->dlightbits, s->polys);
735                 wv = wvert;
736                 wp = &wallpoly[currentwallpoly];
737                 out = &wallvert[currentwallvert];
738                 outcolor = &wallvertcolor[currentwallvert];
739                 currentwallpoly += polys;
740                 for (p = s->polys;p;p = p->next)
741                 {
742                         v = p->verts[0];
743                         wp->texnum = (unsigned short) R_GetTexture(t->texture);
744                         wp->lighttexnum = (unsigned short) (lightmap_textures + s->lightmaptexturenum);
745                         wp->glowtexnum = (unsigned short) R_GetTexture(t->glowtexture);
746                         wp->firstvert = currentwallvert;
747                         wp->numverts = p->numverts;
748                         wp->lit = lit;
749                         wp++;
750                         currentwallvert += p->numverts;
751                         for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, wv += 6, out++, outcolor++)
752                         {
753                                 if (lit)
754                                 {
755                                         if (lighthalf)
756                                         {
757                                                 outcolor->r = (byte) (bound(0, (int) wv[3] >> 1, 255));
758                                                 outcolor->g = (byte) (bound(0, (int) wv[4] >> 1, 255));
759                                                 outcolor->b = (byte) (bound(0, (int) wv[5] >> 1, 255));
760                                                 outcolor->a = 255;
761                                         }
762                                         else
763                                         {
764                                                 outcolor->r = (byte) (bound(0, (int) wv[3], 255));
765                                                 outcolor->g = (byte) (bound(0, (int) wv[4], 255));
766                                                 outcolor->b = (byte) (bound(0, (int) wv[5], 255));
767                                                 outcolor->a = 255;
768                                         }
769                                 }
770                                 out->vert[0] = wv[0];
771                                 out->vert[1] = wv[1];
772                                 out->vert[2] = wv[2];
773                                 out->vert[3] = v[3];
774                                 out->vert[4] = v[4];
775                                 out->vert[5] = v[5];
776                                 out->vert[6] = v[6];
777                         }
778                 }
779         }
780 }
781
782 // LordHavoc: transparent brush models
783 void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmodel)
784 {
785         int i, alpha, size3;
786         float *v, *wv, scale;
787         glpoly_t *p;
788         byte *lm;
789         alpha = (int) (modelalpha * 255.0f);
790         size3 = ((s->extents[0]>>4)+1)*((s->extents[1]>>4)+1)*3; // *3 for colored lighting
791         wv = wvert;
792         for (p = s->polys;p;p = p->next)
793         {
794                 for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE)
795                 {
796                         if (transform)
797                                 softwaretransform(v, wv);
798                         else
799                                 VectorCopy(v, wv);
800                         wv[3] = wv[4] = wv[5] = r_ambient.value * 2.0f;
801                         if (s->styles[0] != 255)
802                         {
803                                 lm = (byte *)((long) s->samples + (int) v[7]);
804                                 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;
805                                 if (s->styles[1] != 255)
806                                 {
807                                         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;
808                                         if (s->styles[2] != 255)
809                                         {
810                                                 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;
811                                                 if (s->styles[3] != 255)
812                                                 {
813                                                         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;
814                                                 }
815                                         }
816                                 }
817                         }
818                         wv += 6;
819                 }
820         }
821         if (s->dlightframe == r_framecount)
822                 RSurf_Light(s->dlightbits, s->polys);
823         wv = wvert;
824         if (isbmodel && (currententity->render.colormod[0] != 1 || currententity->render.colormod[1] != 1 || currententity->render.colormod[2] != 1))
825         {
826                 for (p = s->polys;p;p = p->next)
827                 {
828                         v = p->verts[0];
829                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
830                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
831                                 transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3] * currententity->render.colormod[0], wv[4] * currententity->render.colormod[1], wv[5] * currententity->render.colormod[2], alpha);
832                         transpolyend();
833                 }
834         }
835         else
836         {
837                 for (p = s->polys;p;p = p->next)
838                 {
839                         v = p->verts[0];
840                         transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA);
841                         for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6)
842                                 transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3], wv[4], wv[5], alpha);
843                         transpolyend();
844                 }
845         }
846 }
847
848 void R_NoVisMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, model_t *model);
849
850 float bmverts[256*3];
851
852 int vertexworld;
853
854 /*
855 void RBrushModelSurf_DoVisible(msurface_t *surf)
856 {
857 //      float *v, *bmv, *endbmv;
858 //      glpoly_t *p;
859 //      for (p = surf->polys;p;p = p->next)
860 //      {
861 //              for (v = p->verts[0], bmv = bmpoints, endbmv = bmv + p->numverts * 3;bmv < endbmv;v += VERTEXSIZE, bmv += 3)
862 //                      softwaretransform(v, bmv);
863 //              if (R_Clip_Polygon(bmpoints, p->numverts, sizeof(float) * 3, surf->flags & SURF_CLIPSOLID))
864                         surf->visframe = r_framecount;
865 //      }
866 }
867 */
868
869 void RBrushModelSurf_Callback(void *data, void *data2)
870 {
871         entity_t *ent = data2;
872         msurface_t *surf = data;
873         texture_t *t;
874
875         /*
876         // FIXME: implement better dupe prevention in AddPolygon callback code
877         if (ent->render.model->firstmodelsurface != 0)
878         {
879                 // it's not an instanced model, so we already rely on there being only one of it (usually a valid assumption, but QC can break this)
880                 if (surf->visframe == r_framecount)
881                         return;
882         }
883         */
884         surf->visframe = r_framecount;
885
886         c_faces++;
887
888         currententity = ent;
889         modelalpha = ent->render.alpha;
890
891         softwaretransformforbrushentity (ent);
892
893         if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
894         {
895                 // sky and liquid don't need sorting (skypoly/transpoly)
896                 if (surf->flags & SURF_DRAWSKY)
897                         RSurf_DrawSky(surf, true);
898                 else
899                         RSurf_DrawWater(surf, R_TextureAnimation(surf->texinfo->texture), true, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
900         }
901         else
902         {
903                 t = R_TextureAnimation(surf->texinfo->texture);
904                 if (surf->texinfo->texture->transparent || vertexworld || ent->render.alpha != 1 || ent->render.model->firstmodelsurface == 0 || (ent->render.effects & EF_FULLBRIGHT) || ent->render.colormod[0] != 1 || ent->render.colormod[2] != 1 || ent->render.colormod[2] != 1)
905                         RSurf_DrawWallVertex(surf, t, true, true);
906                 else
907                         RSurf_DrawWall(surf, t, true);
908         }
909 }
910
911 /*
912 =================
913 R_DrawBrushModel
914 =================
915 */
916 void R_DrawBrushModel (entity_t *e)
917 {
918         int                     i, j;
919         vec3_t          mins, maxs;
920         msurface_t      *s;
921         model_t         *clmodel;
922         int                     rotated;
923         vec3_t          org;
924         glpoly_t        *p;
925
926         currententity = e;
927
928         clmodel = e->render.model;
929
930         if (e->render.angles[0] || e->render.angles[1] || e->render.angles[2])
931         {
932                 rotated = true;
933                 for (i=0 ; i<3 ; i++)
934                 {
935                         mins[i] = e->render.origin[i] - clmodel->radius;
936                         maxs[i] = e->render.origin[i] + clmodel->radius;
937                 }
938         }
939         else
940         {
941                 rotated = false;
942                 VectorAdd (e->render.origin, clmodel->mins, mins);
943                 VectorAdd (e->render.origin, clmodel->maxs, maxs);
944         }
945
946         if (R_CullBox (mins, maxs))
947                 return;
948
949         c_bmodels++;
950
951         VectorSubtract (r_origin, e->render.origin, modelorg);
952         if (rotated)
953         {
954                 vec3_t  temp;
955                 vec3_t  forward, right, up;
956
957                 VectorCopy (modelorg, temp);
958                 AngleVectors (e->render.angles, forward, right, up);
959                 modelorg[0] = DotProduct (temp, forward);
960                 modelorg[1] = -DotProduct (temp, right);
961                 modelorg[2] = DotProduct (temp, up);
962         }
963
964         softwaretransformforbrushentity (e);
965
966         for (i = 0, s = &clmodel->surfaces[clmodel->firstmodelsurface];i < clmodel->nummodelsurfaces;i++, s++)
967         {
968                 s->visframe = -1;
969                 if (((s->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, s->plane) >= 0))
970                         s->visframe = r_framecount;
971         }
972
973 // calculate dynamic lighting for bmodel if it's not an instanced model
974         for (i = 0;i < MAX_DLIGHTS;i++)
975         {
976                 if (!cl_dlights[i].radius)
977                         continue;
978
979                 VectorSubtract(cl_dlights[i].origin, currententity->render.origin, org);
980                 R_NoVisMarkLights (org, &cl_dlights[i], 1<<(i&31), i >> 5, clmodel);
981         }
982 //      vertexlit = modelalpha != 1 || clmodel->firstmodelsurface == 0 || (currententity->render.effects & EF_FULLBRIGHT) || currententity->render.colormod[0] != 1 || currententity->render.colormod[2] != 1 || currententity->render.colormod[2] != 1;
983
984         // draw texture
985         for (i = 0, s = &clmodel->surfaces[clmodel->firstmodelsurface];i < clmodel->nummodelsurfaces;i++, s++)
986         {
987                 if (s->visframe == r_framecount)
988                 {
989 //                      R_DrawSurf(s, true, vertexlit || s->texinfo->texture->transparent);
990                         for (p = s->polys;p;p = p->next)
991                         {
992                                 for (j = 0;j < p->numverts;j++)
993                                         softwaretransform(&p->verts[j][0], bmverts + j * 3);
994                                 R_Clip_AddPolygon(bmverts, p->numverts, 3 * sizeof(float), (s->flags & SURF_CLIPSOLID) != 0 && modelalpha == 1, RBrushModelSurf_Callback, s, e, NULL);
995                         }
996                         /*
997                         if (s->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
998                         {
999                                 // sky and liquid don't need sorting (skypoly/transpoly)
1000                                 if (s->flags & SURF_DRAWSKY)
1001                                         RSurf_DrawSky(s, true);
1002                                 else
1003                                         RSurf_DrawWater(s, R_TextureAnimation(s->texinfo->texture), true, s->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
1004                         }
1005                         else
1006                         {
1007                                 texture_t *t = R_TextureAnimation(s->texinfo->texture);
1008                                 if (vertexlit || s->texinfo->texture->transparent)
1009                                         RSurf_DrawWallVertex(s, t, true, true);
1010                                 else
1011                                         RSurf_DrawWall(s, t, true);
1012                         }
1013                         */
1014                 }
1015         }
1016         UploadLightmaps();
1017 }
1018
1019 /*
1020 =============================================================
1021
1022         WORLD MODEL
1023
1024 =============================================================
1025 */
1026
1027 /*
1028 static byte *worldvis;
1029
1030 void R_MarkLeaves (void)
1031 {
1032         static float noviscache;
1033         if (r_oldviewleaf == r_viewleaf && noviscache == r_novis.value)
1034                 return;
1035
1036         r_oldviewleaf = r_viewleaf;
1037         noviscache = r_novis.value;
1038
1039         worldvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
1040 }
1041 */
1042
1043 void RSurf_Callback(void *data, void *junk)
1044 {
1045         ((msurface_t *)data)->visframe = r_framecount;
1046 }
1047
1048 /*
1049 void RSurf_Callback(void *data, void *junk)
1050 {
1051         msurface_t *surf = data;
1052         texture_t *t;
1053
1054 //      if (surf->visframe == r_framecount)
1055 //              return;
1056
1057         surf->visframe = r_framecount;
1058
1059         c_faces++;
1060
1061         if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
1062         {
1063                 // sky and liquid don't need sorting (skypoly/transpoly)
1064                 if (surf->flags & SURF_DRAWSKY)
1065                         RSurf_DrawSky(surf, false);
1066                 else
1067                         RSurf_DrawWater(surf, R_TextureAnimation(surf->texinfo->texture), false, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
1068         }
1069         else
1070         {
1071                 t = R_TextureAnimation(surf->texinfo->texture);
1072                 if (vertexworld)
1073                         RSurf_DrawWallVertex(surf, t, false, false);
1074                 else
1075                         RSurf_DrawWall(surf, t, false);
1076         }
1077 }
1078 */
1079
1080 /*
1081 mleaf_t *r_oldviewleaf;
1082 int r_markvisframecount = 0;
1083
1084 void R_MarkLeaves (void)
1085 {
1086         static float noviscache;
1087         int i, l, k, c;
1088         mleaf_t *leaf;
1089         msurface_t *surf, **mark, **endmark;
1090         model_t *model = cl.worldmodel;
1091 //      mportal_t *portal;
1092         glpoly_t *p;
1093         byte    *in;
1094         int             row;
1095
1096         // ignore testvis if the map just changed
1097         if (r_testvis.value && model->nodes->markvisframe == r_markvisframecount)
1098                 return;
1099
1100         if (r_oldviewleaf == r_viewleaf && noviscache == r_novis.value)
1101                 return;
1102
1103         r_oldviewleaf = r_viewleaf;
1104         noviscache = r_novis.value;
1105
1106         if ((in = r_viewleaf->compressed_vis))
1107         {
1108                 row = (model->numleafs+7)>>3;
1109
1110                 if (!r_testvis.value)
1111                         r_markvisframecount++;
1112
1113                 // LordHavoc: mark the root node as visible, it will terminate all other ascensions
1114                 model->nodes->markvisframe = r_markvisframecount;
1115
1116                 k = 0;
1117                 while (k < row)
1118                 {
1119                         c = *in++;
1120                         if (c)
1121                         {
1122                                 l = model->numleafs - (k << 3);
1123                                 if (l > 8)
1124                                         l = 8;
1125                                 for (i=0 ; i<l ; i++)
1126                                 {
1127                                         if (c & (1<<i))
1128                                         {
1129                                                 leaf = &model->leafs[(k << 3)+i+1];
1130                                                 node = (mnode_t *)leaf;
1131                                                 do
1132                                                 {
1133                                                         node->markvisframe = r_markvisframecount;
1134                                                         node = node->parent;
1135                                                 }
1136                                                 while (node->markvisframecount != r_markvisframecount);
1137                                         }
1138                                 }
1139                                 k++;
1140                         }
1141                         else
1142                                 k += *in++;
1143                 }
1144         }
1145         else
1146         {
1147                 // LordHavoc: no vis data, mark everything as visible
1148                 model->nodes->markvisframe = r_markvisframecount;
1149
1150                 for (i = 1;i < model->numleafs;i++)
1151                 {
1152                         node = (mnode_t *)&model->leafs[i];
1153                         do
1154                         {
1155                                 node->markvisframe = r_markvisframecount;
1156                                 node = node->parent;
1157                         }
1158                         while (node->markvisframecount != r_markvisframecount);
1159                 }
1160         }
1161 }
1162 */
1163
1164 void R_SolidWorldNode (void)
1165 {
1166         if ((int) r_solidworldnode.value == 2)
1167         {
1168                 mnode_t *nodestack[8192], *node = cl.worldmodel->nodes;
1169                 int nodestackpos = 0;
1170                 glpoly_t *p;
1171
1172 loc0:
1173                 if (node->numsurfaces)
1174                 {
1175                         msurface_t *surf = cl.worldmodel->surfaces + node->firstsurface, *surfend = surf + node->numsurfaces;
1176                         tinyplane_t plane;
1177                         if (PlaneDiff (r_origin, node->plane) < 0)
1178                         {
1179                                 for (;surf < surfend;surf++)
1180                                 {
1181                                         if (surf->flags & SURF_PLANEBACK)
1182                                         {
1183                                                 VectorNegate(surf->plane->normal, plane.normal);
1184                                                 plane.dist = -surf->plane->dist;
1185                                                 for (p = surf->polys;p;p = p->next)
1186                                                         R_Clip_AddPolygon((float *)p->verts, p->numverts, VERTEXSIZE * sizeof(float), surf->flags & SURF_CLIPSOLID, RSurf_Callback, surf, NULL, &plane);
1187                                         }
1188                                 }
1189                         }
1190                         else
1191                         {
1192                                 for (;surf < surfend;surf++)
1193                                 {
1194                                         if (!(surf->flags & SURF_PLANEBACK))
1195                                                 for (p = surf->polys;p;p = p->next)
1196                                                         R_Clip_AddPolygon((float *)p->verts, p->numverts, VERTEXSIZE * sizeof(float), surf->flags & SURF_CLIPSOLID, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
1197                                 }
1198                         }
1199                 }
1200
1201                 // recurse down the children
1202                 if (node->children[0]->contents >= 0)
1203                 {
1204                         if (node->children[1]->contents >= 0)
1205                         {
1206                                 if (nodestackpos < 8192)
1207                                         nodestack[nodestackpos++] = node->children[1];
1208                                 node = node->children[0];
1209                                 goto loc0;
1210                         }
1211                         node = node->children[0];
1212                         goto loc0;
1213                 }
1214                 else if (node->children[1]->contents >= 0)
1215                 {
1216                         node = node->children[1];
1217                         goto loc0;
1218                 }
1219                 else if (nodestackpos > 0)
1220                 {
1221                         node = nodestack[--nodestackpos];
1222                         goto loc0;
1223                 }
1224         }
1225         else if ((int) r_solidworldnode.value == 1)
1226         {
1227                 glpoly_t *p;
1228                 msurface_t *surf, *endsurf;
1229                 tinyplane_t plane;
1230
1231
1232                 surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface];
1233                 endsurf = surf + cl.worldmodel->nummodelsurfaces;
1234                 for (;surf < endsurf;surf++)
1235                 {
1236                         if (PlaneDiff(r_origin, surf->plane) < 0)
1237                         {
1238                                 if (surf->flags & SURF_PLANEBACK)
1239                                 {
1240                                         VectorNegate(surf->plane->normal, plane.normal);
1241                                         plane.dist = -surf->plane->dist;
1242                                         for (p = surf->polys;p;p = p->next)
1243                                                 R_Clip_AddPolygon((float *)p->verts, p->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
1244                                 }
1245                         }
1246                         else
1247                         {
1248                                 if (!(surf->flags & SURF_PLANEBACK))
1249                                         for (p = surf->polys;p;p = p->next)
1250                                                 R_Clip_AddPolygon((float *)p->verts, p->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)&surf->plane);
1251                         }
1252                 }
1253         }
1254         else
1255         {
1256                 int l;
1257                 mleaf_t *leaf;
1258                 msurface_t *surf, **mark, **endmark;
1259                 glpoly_t *p;
1260                 tinyplane_t plane;
1261
1262                 for (l = 0, leaf = cl.worldmodel->leafs;l < cl.worldmodel->numleafs;l++, leaf++)
1263                 {
1264                         if (R_CullBox(leaf->mins, leaf->maxs))
1265                                 continue;
1266 //                      leaf->visframe = r_framecount;
1267                         c_leafs++;
1268                         if (leaf->nummarksurfaces)
1269                         {
1270 //                              if (R_CullBox(leaf->mins, leaf->maxs))
1271 //                                      continue;
1272
1273                                 if (leaf->nummarksurfaces)
1274                                 {
1275                                         mark = leaf->firstmarksurface;
1276                                         endmark = mark + leaf->nummarksurfaces;
1277                                         do
1278                                         {
1279                                                 surf = *mark++;
1280                                                 // make sure surfaces are only processed once
1281                                                 if (surf->worldnodeframe == r_framecount)
1282                                                         continue;
1283                                                 surf->worldnodeframe = r_framecount;
1284                                                 if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1285                                                 {
1286                                                         if (surf->flags & SURF_PLANEBACK)
1287                                                         {
1288                                                                 VectorNegate(surf->plane->normal, plane.normal);
1289                                                                 plane.dist = -surf->plane->dist;
1290                                                                 for (p = surf->polys;p;p = p->next)
1291                                                                         R_Clip_AddPolygon((float *)p->verts, p->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
1292                                                         }
1293                                                 }
1294                                                 else
1295                                                 {
1296                                                         if (!(surf->flags & SURF_PLANEBACK))
1297                                                                 for (p = surf->polys;p;p = p->next)
1298                                                                         R_Clip_AddPolygon((float *)p->verts, p->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
1299                                                 }
1300                                         }
1301                                         while (mark < endmark);
1302                                 }
1303                         }
1304                 }
1305         }
1306 }
1307
1308 /*
1309 void RSurf_Callback(void *data, void *junk)
1310 {
1311         ((msurface_t *)data)->visframe = r_framecount;
1312 }
1313
1314 int R_FrustumTestPolygon(float *points, int numpoints, int stride);
1315
1316 void RSurf_DoVisible(msurface_t *surf)
1317 {
1318         glpoly_t *p;
1319         for (p = surf->polys;p;p = p->next)
1320                 if (R_FrustumTestPolygon((float *) p->verts, p->numverts, VERTEXSIZE * sizeof(float)) >= 3)
1321 //              R_Clip_Polygon((float *) p->verts, p->numverts, VERTEXSIZE * sizeof(float), true, RSurf_Callback, surf, 1);
1322 //              if (R_Clip_Polygon((float *) p->verts, p->numverts, VERTEXSIZE * sizeof(float), surf->flags & SURF_CLIPSOLID))
1323                         surf->visframe = r_framecount;
1324 }
1325 */
1326
1327 //mleaf_t *llistbuffer[32768], *l, **llist;
1328
1329 /*
1330 void RSurfLeaf_Callback(void *data)
1331 {
1332         int portalstackpos = 0;
1333         mleaf_t *leaf;
1334         mportal_t *p, *portalstack[32768];
1335         msurface_t *surf, **mark, **endmark;
1336         do
1337         {
1338
1339                 leaf = data;
1340                 if (leaf->visframe == r_framecount)
1341                         return;
1342                 leaf->visframe = r_framecount;
1343
1344                 c_leafs++;
1345
1346                 if (leaf->nummarksurfaces)
1347                 {
1348                         mark = leaf->firstmarksurface;
1349                         endmark = mark + leaf->nummarksurfaces;
1350                         do
1351                         {
1352                                 surf = *mark++;
1353                                 // make sure surfaces are only processed once
1354                                 if (surf->worldnodeframe == r_framecount)
1355                                         continue;
1356                                 surf->worldnodeframe = r_framecount;
1357                                 if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1358                                 {
1359                                         if (surf->flags & SURF_PLANEBACK)
1360                                                 RSurf_DoVisible(surf);
1361                                 }
1362                                 else
1363                                 {
1364                                         if (!(surf->flags & SURF_PLANEBACK))
1365                                                 RSurf_DoVisible(surf);
1366                                 }
1367                         }
1368                         while (mark < endmark);
1369                 }
1370
1371                 // follow portals into other leafs
1372                 for (p = leaf->portals;p;p = p->next)
1373                 {
1374                         if (p->past->visframe != r_framecount && DotProduct(r_origin, p->plane.normal) < p->plane.dist)
1375                         {
1376         //                      R_Clip_Portal((float *) p->points, p->numpoints, sizeof(float) * 3, RSurfLeaf_Callback, p->past, 1);
1377                                 if (R_Clip_Portal((float *) p->points, p->numpoints, sizeof(float) * 3))
1378                                         portalstack[portalstackpos++] = p;
1379                         }
1380                 }
1381         }
1382         while(portalstackpos);
1383         RSurfLeaf_Callback(p->past);
1384         // upon returning, R_ProcessSpans will notice that the spans have changed and restart the line, this is ok because we're not adding any polygons that aren't already behind the portal
1385 }
1386 */
1387
1388 /*
1389 // experimental and inferior to the other in recursion depth allowances
1390 void R_PortalWorldNode (void)
1391 {
1392 //      int i, j;
1393         mportal_t *p;
1394         msurface_t *surf, **mark, **endmark;
1395         mleaf_t *leaf, *llistbuffer[32768], **l, **llist;
1396
1397         leaf = r_viewleaf;
1398         leaf->visframe = r_framecount;
1399         l = llist = &llistbuffer[0];
1400         *llist++ = r_viewleaf;
1401         while (l < llist)
1402         {
1403                 leaf = *l++;
1404
1405                 c_leafs++;
1406
1407                 if (leaf->nummarksurfaces)
1408                 {
1409                         mark = leaf->firstmarksurface;
1410                         endmark = mark + leaf->nummarksurfaces;
1411                         do
1412                         {
1413                                 surf = *mark++;
1414                                 // make sure surfaces are only processed once
1415                                 if (surf->worldnodeframe == r_framecount)
1416                                         continue;
1417                                 surf->worldnodeframe = r_framecount;
1418                                 if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1419                                 {
1420                                         if (surf->flags & SURF_PLANEBACK)
1421                                                 RSurf_DoVisible(surf);
1422                                 }
1423                                 else
1424                                 {
1425                                         if (!(surf->flags & SURF_PLANEBACK))
1426                                                 RSurf_DoVisible(surf);
1427                                 }
1428                         }
1429                         while (mark < endmark);
1430                 }
1431
1432                 // follow portals into other leafs
1433                 for (p = leaf->portals;p;p = p->next)
1434                 {
1435                         if (p->past->visframe != r_framecount)
1436                         {
1437                                 if (R_Clip_Portal((float *) p->points, p->numpoints, sizeof(float) * 3))
1438                                 {
1439                                         p->past->visframe = r_framecount;
1440                                         *llist++ = p->past;
1441                                 }
1442                         }
1443                 }
1444
1445 //              for (p = leaf->portals;p;p = p->next)
1446 //              {
1447 //                      leaf = p->past;
1448 //                      if (leaf->worldnodeframe != r_framecount)
1449 //                      {
1450 //                              leaf->worldnodeframe = r_framecount;
1451 //                              i = (leaf - cl.worldmodel->leafs) - 1;
1452 //                              if ((worldvis[i>>3] & (1<<(i&7))) && R_NotCulledBox(leaf->mins, leaf->maxs))
1453 //                                      *llist++ = leaf;
1454 //                      }
1455 //              }
1456         }
1457
1458 //      i = 0;
1459 //      j = 0;
1460 //      p = r_viewleaf->portals;
1461 //      for (;p;p = p->next)
1462 //      {
1463 //              j++;
1464 //              if (p->past->worldnodeframe != r_framecount)
1465 //                      i++;
1466 //      }
1467 //      if (i)
1468 //              Con_Printf("%i portals of viewleaf (%i portals) were not checked\n", i, j);
1469 }
1470 */
1471
1472
1473 int r_portalframecount = 0;
1474
1475 /*
1476 void R_Portal_Callback(void *data, void *data2)
1477 {
1478         mleaf_t *leaf = data;
1479         if (!r_testvis.value)
1480                 ((mportal_t *)data2)->visframe = r_portalframecount;
1481         if (leaf->visframe != r_framecount)
1482         {
1483                 c_leafs++;
1484                 leaf->visframe = r_framecount;
1485         }
1486 }
1487 */
1488
1489 void R_PVSWorldNode()
1490 {
1491         int i/*, l*/, k, c, row, numbits, bit, leafnum, numleafs;
1492         mleaf_t *leaf;
1493         msurface_t *surf, **mark, **endmark;
1494         model_t *model = cl.worldmodel;
1495         byte *in;
1496 //      mportal_t *portal;
1497         glpoly_t *p;
1498         tinyplane_t plane;
1499
1500 //      c_leafs++;
1501 //      r_viewleaf->visframe = r_framecount;
1502         if (!r_testvis.value)
1503                 r_portalframecount++;
1504
1505         numleafs = model->numleafs;
1506         numbits = numleafs;
1507         k = 0;
1508         in = r_viewleaf->compressed_vis;
1509         row = (numbits + 7) >> 3;
1510         while (k < row)
1511         {
1512                 c = *in++;
1513                 if (c)
1514                 {
1515                         for (i = 0, bit = 1;c;i++, bit <<= 1)
1516                         {
1517                                 if (c & bit)
1518                                 {
1519                                         leafnum = (k << 3)+i+1;
1520                                         if (leafnum > numleafs)
1521                                                 return;
1522                                         c -= bit;
1523                                         leaf = &model->leafs[leafnum];
1524                                         if (R_NotCulledBox(leaf->mins, leaf->maxs))
1525                                         {
1526                                                 //for (portal = leaf->portals;portal;portal = portal->next)
1527                                                 //      if (DotProduct(r_origin, portal->plane.normal) > portal->plane.dist)
1528                                                 //              R_Clip_AddPolygon((float *)portal->points, portal->numpoints, sizeof(mvertex_t), false, R_Portal_Callback, leaf, portal, portal->plane);
1529                                                 //leaf->visframe = r_framecount;
1530                                                 c_leafs++;
1531                                                 if (leaf->nummarksurfaces)
1532                                                 {
1533                                                         mark = leaf->firstmarksurface;
1534                                                         endmark = mark + leaf->nummarksurfaces;
1535                                                         do
1536                                                         {
1537                                                                 surf = *mark++;
1538                                                                 // make sure surfaces are only processed once
1539                                                                 if (surf->worldnodeframe == r_framecount)
1540                                                                         continue;
1541                                                                 surf->worldnodeframe = r_framecount;
1542                                                                 if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1543                                                                 {
1544                                                                         if (surf->flags & SURF_PLANEBACK)
1545                                                                         {
1546                                                                                 VectorNegate(surf->plane->normal, plane.normal);
1547                                                                                 plane.dist = -surf->plane->dist;
1548                                                                                 for (p = surf->polys;p;p = p->next)
1549                                                                                         R_Clip_AddPolygon((float *)p->verts, p->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, &plane);
1550                                                                         }
1551                                                                 }
1552                                                                 else
1553                                                                 {
1554                                                                         if (!(surf->flags & SURF_PLANEBACK))
1555                                                                                 for (p = surf->polys;p;p = p->next)
1556                                                                                         R_Clip_AddPolygon((float *)p->verts, p->numverts, VERTEXSIZE * sizeof(float), (surf->flags & SURF_CLIPSOLID) != 0, RSurf_Callback, surf, NULL, (tinyplane_t *)surf->plane);
1557                                                                 }
1558                                                         }
1559                                                         while (mark < endmark);
1560                                                 }
1561                                         }
1562                                 }
1563                         }
1564                         k++;
1565                 }
1566                 else
1567                         k += *in++;
1568         }
1569 }
1570
1571 /*
1572 void R_OldPortalWorldNode (void)
1573 {
1574         int portalstack, i;
1575         mportal_t *p, *pstack[8192];
1576         msurface_t *surf, **mark, **endmark;
1577         mleaf_t *leaf;
1578
1579         leaf = r_viewleaf;
1580         leaf->worldnodeframe = r_framecount;
1581         portalstack = 0;
1582 loc0:
1583         c_leafs++;
1584
1585         leaf->visframe = r_framecount;
1586
1587         if (leaf->nummarksurfaces)
1588         {
1589                 mark = leaf->firstmarksurface;
1590                 endmark = mark + leaf->nummarksurfaces;
1591                 do
1592                 {
1593                         surf = *mark++;
1594                         // make sure surfaces are only processed once
1595                         if (surf->worldnodeframe == r_framecount)
1596                                 continue;
1597                         surf->worldnodeframe = r_framecount;
1598                         if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
1599                         {
1600                                 if (surf->flags & SURF_PLANEBACK)
1601                                         surf->visframe = r_framecount;
1602                         }
1603                         else
1604                         {
1605                                 if (!(surf->flags & SURF_PLANEBACK))
1606                                         surf->visframe = r_framecount;
1607                         }
1608                 }
1609                 while (mark < endmark);
1610         }
1611
1612         // follow portals into other leafs
1613         p = leaf->portals;
1614         for (;p;p = p->next)
1615         {
1616                 leaf = p->past;
1617                 if (leaf->worldnodeframe != r_framecount)
1618                 {
1619                         leaf->worldnodeframe = r_framecount;
1620                         if (leaf->contents != CONTENTS_SOLID)
1621                         {
1622                                 i = (leaf - cl.worldmodel->leafs) - 1;
1623                                 if (worldvis[i>>3] & (1<<(i&7)))
1624                                 {
1625                                         if (R_NotCulledBox(leaf->mins, leaf->maxs))
1626                                         {
1627                                                 pstack[portalstack++] = p;
1628                                                 goto loc0;
1629
1630 loc1:
1631                                                 p = pstack[--portalstack];
1632                                         }
1633                                 }
1634                         }
1635                 }
1636         }
1637
1638         if (portalstack)
1639                 goto loc1;
1640
1641         i = 0;
1642         portalstack = 0;
1643         p = r_viewleaf->portals;
1644         for (;p;p = p->next)
1645         {
1646                 portalstack++;
1647                 if (p->past->worldnodeframe != r_framecount)
1648                         i++;
1649         }
1650         if (i)
1651                 Con_Printf("%i portals of viewleaf (%i portals) were not checked\n", i, portalstack);
1652 }
1653 */
1654
1655 entity_t clworldent;
1656
1657 void R_DrawSurfaces (void)
1658 {
1659         msurface_t      *surf, *endsurf;
1660         texture_t       *t, *currentt;
1661         int vertex = gl_vertex.value;
1662
1663         currententity = &clworldent;
1664         modelalpha = 1;
1665         softwaretransformidentity();
1666         surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface];
1667         endsurf = surf + cl.worldmodel->nummodelsurfaces;
1668         t = currentt = NULL;
1669         for (;surf < endsurf;surf++)
1670         {
1671                 if (surf->visframe == r_framecount)
1672                 {
1673                         c_faces++;
1674                         if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
1675                         {
1676                                 // sky and liquid don't need sorting (skypoly/transpoly)
1677                                 if (surf->flags & SURF_DRAWSKY)
1678                                         RSurf_DrawSky(surf, false);
1679                                 else
1680                                 {
1681                                         if (currentt != surf->texinfo->texture)
1682                                         {
1683                                                 currentt = surf->texinfo->texture;
1684                                                 t = R_TextureAnimation(surf->texinfo->texture);
1685                                         }
1686                                         RSurf_DrawWater(surf, t, false, surf->flags & SURF_DRAWNOALPHA ? 255 : wateralpha);
1687                                 }
1688                         }
1689                         else
1690                         {
1691                                 if (currentt != surf->texinfo->texture)
1692                                 {
1693                                         currentt = surf->texinfo->texture;
1694                                         t = R_TextureAnimation(surf->texinfo->texture);
1695                                 }
1696                                 if (vertex)
1697                                         RSurf_DrawWallVertex(surf, t, false, false);
1698                                 else
1699                                         RSurf_DrawWall(surf, t, false);
1700                         }
1701                 }
1702         }
1703 }
1704
1705 void R_DrawPortals(void)
1706 {
1707         int drawportals, i, r, g, b;
1708 //      mleaf_t *leaf, *endleaf;
1709         mportal_t *portal, *endportal;
1710         mvertex_t *point/*, *endpoint*/;
1711         drawportals = (int)r_drawportals.value;
1712         if (drawportals < 1)
1713                 return;
1714         /*
1715         leaf = cl.worldmodel->leafs;
1716         endleaf = leaf + cl.worldmodel->numleafs;
1717         for (;leaf < endleaf;leaf++)
1718         {
1719                 if (leaf->visframe == r_framecount && leaf->portals)
1720                 {
1721                         i = leaf - cl.worldmodel->leafs;
1722                         r = (i & 0x0007) << 5;
1723                         g = (i & 0x0038) << 2;
1724                         b = (i & 0x01C0) >> 1;
1725                         portal = leaf->portals;
1726                         while (portal)
1727                         {
1728                                 transpolybegin(0, 0, 0, TPOLYTYPE_ALPHA);
1729                                 point = portal->points + portal->numpoints - 1;
1730                                 endpoint = portal->points;
1731                                 for (;point >= endpoint;point--)
1732                                         transpolyvertub(point->position[0], point->position[1], point->position[2], 0, 0, r, g, b, 32);
1733                                 transpolyend();
1734                                 portal = portal->next;
1735                         }
1736                 }
1737         }
1738         */
1739         portal = cl.worldmodel->portals;
1740         endportal = portal + cl.worldmodel->numportals;
1741         for (;portal < endportal;portal++)
1742         {
1743                 if (portal->visframe == r_portalframecount)
1744                 {
1745                         i = portal - cl.worldmodel->portals;
1746                         r = (i & 0x0007) << 5;
1747                         g = (i & 0x0038) << 2;
1748                         b = (i & 0x01C0) >> 1;
1749                         transpolybegin(0, 0, 0, TPOLYTYPE_ALPHA);
1750                         point = portal->points;
1751                         if (PlaneDiff(r_origin, (&portal->plane)) > 0)
1752                         {
1753                                 for (i = portal->numpoints - 1;i >= 0;i--)
1754                                         transpolyvertub(point[i].position[0], point[i].position[1], point[i].position[2], 0, 0, r, g, b, 32);
1755                         }
1756                         else
1757                         {
1758                                 for (i = 0;i < portal->numpoints;i++)
1759                                         transpolyvertub(point[i].position[0], point[i].position[1], point[i].position[2], 0, 0, r, g, b, 32);
1760                         }
1761                         transpolyend();
1762                 }
1763         }
1764 }
1765
1766 /*
1767 =============
1768 R_DrawWorld
1769 =============
1770 */
1771 void R_DrawWorld (void)
1772 {
1773         wateralpha = bound(0, r_wateralpha.value*255.0f, 255);
1774         vertexworld = gl_vertex.value;
1775
1776         memset (&clworldent, 0, sizeof(clworldent));
1777         clworldent.render.model = cl.worldmodel;
1778         clworldent.render.colormod[0] = clworldent.render.colormod[1] = clworldent.render.colormod[2] = 1;
1779         modelalpha = clworldent.render.alpha = 1;
1780         clworldent.render.scale = 1;
1781
1782         VectorCopy (r_origin, modelorg);
1783
1784         currententity = &clworldent;
1785
1786         softwaretransformidentity(); // LordHavoc: clear transform
1787
1788         if (cl.worldmodel)
1789         {
1790                 if (r_novis.value || r_viewleaf->compressed_vis == NULL)
1791                         R_SolidWorldNode ();
1792                 else
1793                 {
1794 //                      R_MarkLeaves ();
1795                         R_PVSWorldNode ();
1796                 }
1797         }
1798 }
1799
1800 /*
1801 =============================================================================
1802
1803   LIGHTMAP ALLOCATION
1804
1805 =============================================================================
1806 */
1807
1808 // returns a texture number and the position inside it
1809 int AllocBlock (int w, int h, short *x, short *y)
1810 {
1811         int             i, j;
1812         int             best, best2;
1813         int             texnum;
1814
1815         for (texnum = 0;texnum < MAX_LIGHTMAPS;texnum++)
1816         {
1817                 best = BLOCK_HEIGHT;
1818
1819                 for (i = 0;i < BLOCK_WIDTH - w;i += lightmapalign) // LordHavoc: NVIDIA has broken subimage, so align the lightmaps
1820                 {
1821                         best2 = 0;
1822
1823                         for (j=0 ; j<w ; j++)
1824                         {
1825                                 if (allocated[texnum][i+j] >= best)
1826                                         break;
1827                                 if (allocated[texnum][i+j] > best2)
1828                                         best2 = allocated[texnum][i+j];
1829                         }
1830                         if (j == w)
1831                         {       // this is a valid spot
1832                                 *x = i;
1833                                 *y = best = best2;
1834                         }
1835                 }
1836
1837                 if (best + h > BLOCK_HEIGHT)
1838                         continue;
1839
1840                 if (nosubimagefragments || nosubimage)
1841                 {
1842                         if (!lightmaps[texnum])
1843                         {
1844                                 lightmaps[texnum] = qmalloc(BLOCK_WIDTH*BLOCK_HEIGHT*4);
1845                                 memset(lightmaps[texnum], 0, BLOCK_WIDTH*BLOCK_HEIGHT*4);
1846                         }
1847                 }
1848                 // LordHavoc: clear texture to blank image, fragments are uploaded using subimage
1849                 else if (!allocated[texnum][0])
1850                 {
1851                         byte blank[BLOCK_WIDTH*BLOCK_HEIGHT*4];
1852                         memset(blank, 0, sizeof(blank));
1853                         if(r_upload.value)
1854                         {
1855                                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + texnum);
1856                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1857                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1858                                 if (lightmaprgba)
1859                                         glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank);
1860                                 else
1861                                         glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, blank);
1862                         }
1863                 }
1864
1865                 for (i = 0;i < w;i++)
1866                         allocated[texnum][*x + i] = best + h;
1867
1868                 return texnum;
1869         }
1870
1871         Host_Error ("AllocBlock: full, unable to find room for %i by %i lightmap", w, h);
1872         return 0;
1873 }
1874
1875
1876 //int   nColinElim;
1877
1878 /*
1879 ================
1880 BuildSurfaceDisplayList
1881 ================
1882 */
1883 void BuildSurfaceDisplayList (model_t *model, mvertex_t *vertices, msurface_t *fa)
1884 {
1885         int                     i, j, lindex, lnumverts;
1886         medge_t         *pedges;
1887         float           *vec;
1888         float           s, t;
1889         glpoly_t        *poly;
1890
1891 // reconstruct the polygon
1892         pedges = model->edges;
1893         lnumverts = fa->numedges;
1894
1895         //
1896         // draw texture
1897         //
1898         poly = Hunk_AllocName (sizeof(glpolysizeof_t) + lnumverts * sizeof(float[VERTEXSIZE]), "surfaces");
1899         poly->next = fa->polys;
1900         fa->polys = poly;
1901 //      poly->flags = fa->flags;
1902         poly->numverts = lnumverts;
1903
1904         for (i=0 ; i<lnumverts ; i++)
1905         {
1906                 lindex = model->surfedges[fa->firstedge + i];
1907
1908                 if (lindex > 0)
1909                         vec = vertices[pedges[lindex].v[0]].position;
1910                 else
1911                         vec = vertices[pedges[-lindex].v[1]].position;
1912
1913                 s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
1914                 t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
1915
1916                 VectorCopy (vec, poly->verts[i]);
1917                 poly->verts[i][3] = s / fa->texinfo->texture->width;
1918                 poly->verts[i][4] = t / fa->texinfo->texture->height;
1919
1920                 //
1921                 // lightmap texture coordinates
1922                 //
1923                 s -= fa->texturemins[0];
1924                 t -= fa->texturemins[1];
1925                 s += 8;
1926                 t += 8;
1927                 // LordHavoc: calc lightmap data offset
1928                 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;
1929                 poly->verts[i][7] = j;
1930                 s += fa->light_s*16;
1931                 s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
1932
1933                 t += fa->light_t*16;
1934                 t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
1935
1936                 poly->verts[i][5] = s;
1937                 poly->verts[i][6] = t;
1938         }
1939
1940         //
1941         // remove co-linear points - Ed
1942         //
1943         /*
1944         if (!gl_keeptjunctions.value)
1945         {
1946                 for (i = 0 ; i < lnumverts ; ++i)
1947                 {
1948                         vec3_t v1, v2;
1949                         float *prev, *this, *next;
1950
1951                         prev = poly->verts[(i + lnumverts - 1) % lnumverts];
1952                         this = poly->verts[i];
1953                         next = poly->verts[(i + 1) % lnumverts];
1954
1955                         VectorSubtract( this, prev, v1 );
1956                         VectorNormalize( v1 );
1957                         VectorSubtract( next, prev, v2 );
1958                         VectorNormalize( v2 );
1959
1960                         // skip co-linear points
1961                         #define COLINEAR_EPSILON 0.001
1962                         if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
1963                                 (fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) &&
1964                                 (fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
1965                         {
1966                                 int j;
1967                                 for (j = i + 1; j < lnumverts; ++j)
1968                                 {
1969                                         int k;
1970                                         for (k = 0; k < VERTEXSIZE; ++k)
1971                                                 poly->verts[j - 1][k] = poly->verts[j][k];
1972                                 }
1973                                 --lnumverts;
1974                                 ++nColinElim;
1975                                 // retry next vertex next time, which is now current vertex
1976                                 --i;
1977                         }
1978                 }
1979                 poly->numverts = lnumverts;
1980         }
1981         */
1982 }
1983
1984 /*
1985 ========================
1986 GL_CreateSurfaceLightmap
1987 ========================
1988 */
1989 void GL_CreateSurfaceLightmap (msurface_t *surf)
1990 {
1991         int             smax, tmax;
1992
1993         if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
1994                 return;
1995
1996         smax = (surf->extents[0]>>4)+1;
1997         tmax = (surf->extents[1]>>4)+1;
1998
1999         surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
2000         if (nosubimage || nosubimagefragments)
2001                 return;
2002         glBindTexture(GL_TEXTURE_2D, lightmap_textures + surf->lightmaptexturenum);
2003         smax = ((surf->extents[0]>>4)+lightmapalign) & lightmapalignmask;
2004         if (lightmaprgba)
2005         {
2006                 R_BuildLightMap (surf, templight, smax * 4);
2007                 if(r_upload.value)
2008                         glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight);
2009         }
2010         else
2011         {
2012                 R_BuildLightMap (surf, templight, smax * 3);
2013                 if(r_upload.value)
2014                         glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight);
2015         }
2016 }
2017
2018
2019 /*
2020 ==================
2021 GL_BuildLightmaps
2022
2023 Builds the lightmap texture
2024 with all the surfaces from all brush models
2025 ==================
2026 */
2027 void GL_BuildLightmaps (void)
2028 {
2029         int             i, j;
2030         model_t *m;
2031
2032         memset (allocated, 0, sizeof(allocated));
2033
2034         r_framecount = 1;               // no dlightcache
2035
2036         if (gl_nosubimagefragments.value)
2037                 nosubimagefragments = 1;
2038         else
2039                 nosubimagefragments = 0;
2040
2041         if (gl_nosubimage.value)
2042                 nosubimage = 1;
2043         else
2044                 nosubimage = 0;
2045
2046         if (gl_lightmaprgba.value)
2047         {
2048                 lightmaprgba = true;
2049                 lightmapbytes = 4;
2050         }
2051         else
2052         {
2053                 lightmaprgba = false;
2054                 lightmapbytes = 3;
2055         }
2056
2057         // LordHavoc: NVIDIA seems to have a broken glTexSubImage2D,
2058         //            it needs to be aligned on 4 pixel boundaries...
2059         //            so I implemented an adjustable lightmap alignment
2060         if (gl_lightmapalign.value < 1)
2061                 gl_lightmapalign.value = 1;
2062         if (gl_lightmapalign.value > 16)
2063                 gl_lightmapalign.value = 16;
2064         lightmapalign = 1;
2065         while (lightmapalign < gl_lightmapalign.value)
2066                 lightmapalign <<= 1;
2067         gl_lightmapalign.value = lightmapalign;
2068         lightmapalignmask = ~(lightmapalign - 1);
2069         if (nosubimagefragments || nosubimage)
2070         {
2071                 lightmapalign = 1;
2072                 lightmapalignmask = ~0;
2073         }
2074
2075         if (!lightmap_textures)
2076                 lightmap_textures = R_GetTextureSlots(MAX_LIGHTMAPS);
2077
2078         for (j=1 ; j<MAX_MODELS ; j++)
2079         {
2080                 m = cl.model_precache[j];
2081                 if (!m)
2082                         break;
2083                 if (m->name[0] == '*')
2084                         continue;
2085                 for (i=0 ; i<m->numsurfaces ; i++)
2086                 {
2087                         if ( m->surfaces[i].flags & SURF_DRAWTURB )
2088                                 continue;
2089                         if ( m->surfaces[i].flags & SURF_DRAWSKY )
2090                                 continue;
2091                         GL_CreateSurfaceLightmap (m->surfaces + i);
2092                         BuildSurfaceDisplayList (m, m->vertexes, m->surfaces + i);
2093                 }
2094         }
2095
2096         if (nosubimage || nosubimagefragments)
2097         {
2098                 if(r_upload.value)
2099                         if (gl_mtexable)
2100                                 qglSelectTexture(gl_mtex_enum+1);
2101                 for (i = 0;i < MAX_LIGHTMAPS;i++)
2102                 {
2103                         if (!allocated[i][0])
2104                                 break;
2105                         lightmapupdate[i][0] = BLOCK_HEIGHT;
2106                         lightmapupdate[i][1] = 0;
2107                         if(r_upload.value)
2108                         {
2109                                 glBindTexture(GL_TEXTURE_2D, lightmap_textures + i);
2110                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2111                                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2112                                 if (lightmaprgba)
2113                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]);
2114                                 else
2115                                         glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]);
2116                         }
2117                 }
2118                 if(r_upload.value)
2119                         if (gl_mtexable)
2120                                 qglSelectTexture(gl_mtex_enum+0);
2121         }
2122 }
2123