633007f9bb2f05ff88216eddd465c8978b1da80b
[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 #include "r_shadow.h"
24
25 #define MAX_LIGHTMAP_SIZE 256
26
27 static unsigned int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
28 static float floatblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
29
30 static qbyte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
31
32 cvar_t r_ambient = {0, "r_ambient", "0"};
33 cvar_t r_drawportals = {0, "r_drawportals", "0"};
34 cvar_t r_testvis = {0, "r_testvis", "0"};
35 cvar_t r_floatbuildlightmap = {0, "r_floatbuildlightmap", "0"};
36 cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"};
37 cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "0"};
38 cvar_t r_drawcollisionbrushes_polygonfactor = {0, "r_drawcollisionbrushes_polygonfactor", "-1"};
39 cvar_t r_drawcollisionbrushes_polygonoffset = {0, "r_drawcollisionbrushes_polygonoffset", "0"};
40 cvar_t r_q3bsp_renderskydepth = {0, "r_q3bsp_renderskydepth", "0"};
41 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0"};
42
43 // flag arrays used for visibility checking on world model
44 // (all other entities have no per-surface/per-leaf visibility checks)
45 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_clusters
46 qbyte r_pvsbits[(32768+7)>>3];
47 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_leafs
48 qbyte r_worldleafvisible[32768];
49 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_surfaces
50 qbyte r_worldsurfacevisible[262144];
51
52 #ifdef LHREMOVESOON
53 static int dlightdivtable[32768];
54
55 static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surface)
56 {
57         int sdtable[256], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, smax3, red, green, blue, lit, dist2, impacts, impactt, subtract, k;
58         unsigned int *bl;
59         float dist, impact[3], local[3], planenormal[3], planedist;
60         dlight_t *light;
61
62         lit = false;
63
64         smax = (surface->extents[0] >> 4) + 1;
65         tmax = (surface->extents[1] >> 4) + 1;
66         smax3 = smax * 3;
67
68         VectorCopy(surface->mesh.data_normal3f, planenormal);
69         planedist = DotProduct(surface->mesh.data_vertex3f, planenormal);
70
71         for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
72         {
73                 if (!(surface->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
74                         continue;                                       // not lit by this light
75
76                 Matrix4x4_Transform(matrix, light->origin, local);
77                 dist = DotProduct(local, planenormal) - planedist;
78
79                 // for comparisons to minimum acceptable light
80                 // compensate for LIGHTOFFSET
81                 maxdist = (int) light->rtlight.lightmap_cullradius2 + LIGHTOFFSET;
82
83                 dist2 = dist * dist;
84                 dist2 += LIGHTOFFSET;
85                 if (dist2 >= maxdist)
86                         continue;
87
88                 VectorMA(local, -dist, planenormal, impact);
89
90                 impacts = DotProduct (impact, surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3] - surface->texturemins[0];
91                 impactt = DotProduct (impact, surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3] - surface->texturemins[1];
92
93                 s = bound(0, impacts, smax * 16) - impacts;
94                 t = bound(0, impactt, tmax * 16) - impactt;
95                 i = s * s + t * t + dist2;
96                 if (i > maxdist)
97                         continue;
98
99                 // reduce calculations
100                 for (s = 0, i = impacts; s < smax; s++, i -= 16)
101                         sdtable[s] = i * i + dist2;
102
103                 maxdist3 = maxdist - dist2;
104
105                 // convert to 8.8 blocklights format
106                 red = light->rtlight.lightmap_light[0] * (1.0f / 128.0f);
107                 green = light->rtlight.lightmap_light[1] * (1.0f / 128.0f);
108                 blue = light->rtlight.lightmap_light[2] * (1.0f / 128.0f);
109                 subtract = (int) (light->rtlight.lightmap_subtract * 4194304.0f);
110                 bl = intblocklights;
111
112                 i = impactt;
113                 for (t = 0;t < tmax;t++, i -= 16)
114                 {
115                         td = i * i;
116                         // make sure some part of it is visible on this line
117                         if (td < maxdist3)
118                         {
119                                 maxdist2 = maxdist - td;
120                                 for (s = 0;s < smax;s++)
121                                 {
122                                         if (sdtable[s] < maxdist2)
123                                         {
124                                                 k = dlightdivtable[(sdtable[s] + td) >> 7] - subtract;
125                                                 if (k > 0)
126                                                 {
127                                                         bl[0] += (red   * k);
128                                                         bl[1] += (green * k);
129                                                         bl[2] += (blue  * k);
130                                                         lit = true;
131                                                 }
132                                         }
133                                         bl += 3;
134                                 }
135                         }
136                         else // skip line
137                                 bl += smax3;
138                 }
139         }
140         return lit;
141 }
142
143 static int R_FloatAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surface)
144 {
145         int lnum, s, t, smax, tmax, smax3, lit, impacts, impactt;
146         float sdtable[256], *bl, k, dist, dist2, maxdist, maxdist2, maxdist3, td1, td, red, green, blue, impact[3], local[3], subtract, planenormal[3], planedist;
147         dlight_t *light;
148
149         lit = false;
150
151         smax = (surface->extents[0] >> 4) + 1;
152         tmax = (surface->extents[1] >> 4) + 1;
153         smax3 = smax * 3;
154
155         VectorCopy(surface->mesh.data_normal3f, planenormal);
156         planedist = DotProduct(surface->mesh.data_vertex3f, planenormal);
157
158         for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
159         {
160                 if (!(surface->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
161                         continue;                                       // not lit by this light
162
163                 Matrix4x4_Transform(matrix, light->origin, local);
164                 dist = DotProduct(local, planenormal) - planedist;
165
166                 // for comparisons to minimum acceptable light
167                 // compensate for LIGHTOFFSET
168                 maxdist = (int) light->rtlight.lightmap_cullradius2 + LIGHTOFFSET;
169
170                 dist2 = dist * dist;
171                 dist2 += LIGHTOFFSET;
172                 if (dist2 >= maxdist)
173                         continue;
174
175                 VectorMA(local, -dist, planenormal, impact);
176
177                 impacts = DotProduct (impact, surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3] - surface->texturemins[0];
178                 impactt = DotProduct (impact, surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3] - surface->texturemins[1];
179
180                 td = bound(0, impacts, smax * 16) - impacts;
181                 td1 = bound(0, impactt, tmax * 16) - impactt;
182                 td = td * td + td1 * td1 + dist2;
183                 if (td > maxdist)
184                         continue;
185
186                 // reduce calculations
187                 for (s = 0, td1 = impacts; s < smax; s++, td1 -= 16.0f)
188                         sdtable[s] = td1 * td1 + dist2;
189
190                 maxdist3 = maxdist - dist2;
191
192                 // convert to 8.8 blocklights format
193                 red = light->rtlight.lightmap_light[0];
194                 green = light->rtlight.lightmap_light[1];
195                 blue = light->rtlight.lightmap_light[2];
196                 subtract = light->rtlight.lightmap_subtract * 32768.0f;
197                 bl = floatblocklights;
198
199                 td1 = impactt;
200                 for (t = 0;t < tmax;t++, td1 -= 16.0f)
201                 {
202                         td = td1 * td1;
203                         // make sure some part of it is visible on this line
204                         if (td < maxdist3)
205                         {
206                                 maxdist2 = maxdist - td;
207                                 for (s = 0;s < smax;s++)
208                                 {
209                                         if (sdtable[s] < maxdist2)
210                                         {
211                                                 k = (32768.0f / (sdtable[s] + td)) - subtract;
212                                                 bl[0] += red   * k;
213                                                 bl[1] += green * k;
214                                                 bl[2] += blue  * k;
215                                                 lit = true;
216                                         }
217                                         bl += 3;
218                                 }
219                         }
220                         else // skip line
221                                 bl += smax3;
222                 }
223         }
224         return lit;
225 }
226 #endif
227
228 /*
229 ===============
230 R_BuildLightMap
231
232 Combine and scale multiple lightmaps into the 8.8 format in blocklights
233 ===============
234 */
235 static void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface)
236 {
237         if (!r_floatbuildlightmap.integer)
238         {
239                 int smax, tmax, i, j, size, size3, maps, stride, l;
240                 unsigned int *bl, scale;
241                 qbyte *lightmap, *out, *stain;
242
243                 // update cached lighting info
244                 surface->cached_dlight = 0;
245
246                 smax = (surface->extents[0]>>4)+1;
247                 tmax = (surface->extents[1]>>4)+1;
248                 size = smax*tmax;
249                 size3 = size*3;
250                 lightmap = surface->samples;
251
252         // set to full bright if no light data
253                 bl = intblocklights;
254                 if (!ent->model->brushq1.lightdata)
255                 {
256                         for (i = 0;i < size3;i++)
257                                 bl[i] = 255*256;
258                 }
259                 else
260                 {
261         // clear to no light
262                         memset(bl, 0, size*3*sizeof(unsigned int));
263
264 #ifdef LHREMOVESOON
265                         if (surface->dlightframe == r_framecount)
266                         {
267                                 surface->dlightframe = -1;
268                                 surface->cached_dlight = R_IntAddDynamicLights(&ent->inversematrix, surface);
269                                 if (surface->cached_dlight)
270                                         c_light_polys++;
271                         }
272 #endif
273
274         // add all the lightmaps
275                         if (lightmap)
276                         {
277                                 bl = intblocklights;
278                                 for (maps = 0;maps < MAXLIGHTMAPS && surface->styles[maps] != 255;maps++, lightmap += size3)
279                                         for (scale = d_lightstylevalue[surface->styles[maps]], i = 0;i < size3;i++)
280                                                 bl[i] += lightmap[i] * scale;
281                         }
282                 }
283
284                 stain = surface->stainsamples;
285                 bl = intblocklights;
286                 out = templight;
287                 // the >> 16 shift adjusts down 8 bits to account for the stainmap
288                 // scaling, and remaps the 0-65536 (2x overbright) to 0-256, it will
289                 // be doubled during rendering to achieve 2x overbright
290                 // (0 = 0.0, 128 = 1.0, 256 = 2.0)
291                 if (ent->model->brushq1.lightmaprgba)
292                 {
293                         stride = (surface->lightmaptexturestride - smax) * 4;
294                         for (i = 0;i < tmax;i++, out += stride)
295                         {
296                                 for (j = 0;j < smax;j++)
297                                 {
298                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
299                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
300                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
301                                         *out++ = 255;
302                                 }
303                         }
304                 }
305                 else
306                 {
307                         stride = (surface->lightmaptexturestride - smax) * 3;
308                         for (i = 0;i < tmax;i++, out += stride)
309                         {
310                                 for (j = 0;j < smax;j++)
311                                 {
312                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
313                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
314                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
315                                 }
316                         }
317                 }
318
319                 R_UpdateTexture(surface->lightmaptexture, templight);
320         }
321         else
322         {
323                 int smax, tmax, i, j, size, size3, maps, stride, l;
324                 float *bl, scale;
325                 qbyte *lightmap, *out, *stain;
326
327                 // update cached lighting info
328                 surface->cached_dlight = 0;
329
330                 smax = (surface->extents[0]>>4)+1;
331                 tmax = (surface->extents[1]>>4)+1;
332                 size = smax*tmax;
333                 size3 = size*3;
334                 lightmap = surface->samples;
335
336         // set to full bright if no light data
337                 bl = floatblocklights;
338                 if (!ent->model->brushq1.lightdata)
339                 {
340                         for (i = 0;i < size3;i++)
341                                 bl[i] = 255*256;
342                 }
343                 else
344                 {
345                         memset(bl, 0, size*3*sizeof(float));
346
347 #ifdef LHREMOVESOON
348                         if (surface->dlightframe == r_framecount)
349                         {
350                                 surface->dlightframe = -1;
351                                 surface->cached_dlight = R_FloatAddDynamicLights(&ent->inversematrix, surface);
352                                 if (surface->cached_dlight)
353                                         c_light_polys++;
354                         }
355 #endif
356
357                         // add all the lightmaps
358                         if (lightmap)
359                         {
360                                 bl = floatblocklights;
361                                 for (maps = 0;maps < MAXLIGHTMAPS && surface->styles[maps] != 255;maps++, lightmap += size3)
362                                         for (scale = d_lightstylevalue[surface->styles[maps]], i = 0;i < size3;i++)
363                                                 bl[i] += lightmap[i] * scale;
364                         }
365                 }
366
367                 stain = surface->stainsamples;
368                 bl = floatblocklights;
369                 out = templight;
370                 // this scaling adjusts down 8 bits to account for the stainmap
371                 // scaling, and remaps the 0.0-2.0 (2x overbright) to 0-256, it will
372                 // be doubled during rendering to achieve 2x overbright
373                 // (0 = 0.0, 128 = 1.0, 256 = 2.0)
374                 scale = 1.0f / (1 << 16);
375                 if (ent->model->brushq1.lightmaprgba)
376                 {
377                         stride = (surface->lightmaptexturestride - smax) * 4;
378                         for (i = 0;i < tmax;i++, out += stride)
379                         {
380                                 for (j = 0;j < smax;j++)
381                                 {
382                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
383                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
384                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
385                                         *out++ = 255;
386                                 }
387                         }
388                 }
389                 else
390                 {
391                         stride = (surface->lightmaptexturestride - smax) * 3;
392                         for (i = 0;i < tmax;i++, out += stride)
393                         {
394                                 for (j = 0;j < smax;j++)
395                                 {
396                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
397                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
398                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
399                                 }
400                         }
401                 }
402
403                 R_UpdateTexture(surface->lightmaptexture, templight);
404         }
405 }
406
407 void R_StainNode (mnode_t *node, model_t *model, const vec3_t origin, float radius, const float fcolor[8])
408 {
409         float ndist, a, ratio, maxdist, maxdist2, maxdist3, invradius, sdtable[256], td, dist2;
410         msurface_t *surface, *endsurface;
411         int i, s, t, smax, tmax, smax3, impacts, impactt, stained;
412         qbyte *bl;
413         vec3_t impact;
414
415         maxdist = radius * radius;
416         invradius = 1.0f / radius;
417
418 loc0:
419         if (!node->plane)
420                 return;
421         ndist = PlaneDiff(origin, node->plane);
422         if (ndist > radius)
423         {
424                 node = node->children[0];
425                 goto loc0;
426         }
427         if (ndist < -radius)
428         {
429                 node = node->children[1];
430                 goto loc0;
431         }
432
433         dist2 = ndist * ndist;
434         maxdist3 = maxdist - dist2;
435
436         if (node->plane->type < 3)
437         {
438                 VectorCopy(origin, impact);
439                 impact[node->plane->type] -= ndist;
440         }
441         else
442         {
443                 impact[0] = origin[0] - node->plane->normal[0] * ndist;
444                 impact[1] = origin[1] - node->plane->normal[1] * ndist;
445                 impact[2] = origin[2] - node->plane->normal[2] * ndist;
446         }
447
448         for (surface = model->brush.data_surfaces + node->firstsurface, endsurface = surface + node->numsurfaces;surface < endsurface;surface++)
449         {
450                 if (surface->stainsamples)
451                 {
452                         smax = (surface->extents[0] >> 4) + 1;
453                         tmax = (surface->extents[1] >> 4) + 1;
454
455                         impacts = DotProduct (impact, surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3] - surface->texturemins[0];
456                         impactt = DotProduct (impact, surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3] - surface->texturemins[1];
457
458                         s = bound(0, impacts, smax * 16) - impacts;
459                         t = bound(0, impactt, tmax * 16) - impactt;
460                         i = s * s + t * t + dist2;
461                         if (i > maxdist)
462                                 continue;
463
464                         // reduce calculations
465                         for (s = 0, i = impacts; s < smax; s++, i -= 16)
466                                 sdtable[s] = i * i + dist2;
467
468                         bl = surface->stainsamples;
469                         smax3 = smax * 3;
470                         stained = false;
471
472                         i = impactt;
473                         for (t = 0;t < tmax;t++, i -= 16)
474                         {
475                                 td = i * i;
476                                 // make sure some part of it is visible on this line
477                                 if (td < maxdist3)
478                                 {
479                                         maxdist2 = maxdist - td;
480                                         for (s = 0;s < smax;s++)
481                                         {
482                                                 if (sdtable[s] < maxdist2)
483                                                 {
484                                                         ratio = lhrandom(0.0f, 1.0f);
485                                                         a = (fcolor[3] + ratio * fcolor[7]) * (1.0f - sqrt(sdtable[s] + td) * invradius);
486                                                         if (a >= (1.0f / 64.0f))
487                                                         {
488                                                                 if (a > 1)
489                                                                         a = 1;
490                                                                 bl[0] = (qbyte) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0]));
491                                                                 bl[1] = (qbyte) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1]));
492                                                                 bl[2] = (qbyte) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2]));
493                                                                 stained = true;
494                                                         }
495                                                 }
496                                                 bl += 3;
497                                         }
498                                 }
499                                 else // skip line
500                                         bl += smax3;
501                         }
502                         // force lightmap upload
503                         if (stained)
504                                 surface->cached_dlight = true;
505                 }
506         }
507
508         if (node->children[0]->plane)
509         {
510                 if (node->children[1]->plane)
511                 {
512                         R_StainNode(node->children[0], model, origin, radius, fcolor);
513                         node = node->children[1];
514                         goto loc0;
515                 }
516                 else
517                 {
518                         node = node->children[0];
519                         goto loc0;
520                 }
521         }
522         else if (node->children[1]->plane)
523         {
524                 node = node->children[1];
525                 goto loc0;
526         }
527 }
528
529 void R_Stain (const vec3_t origin, float radius, int cr1, int cg1, int cb1, int ca1, int cr2, int cg2, int cb2, int ca2)
530 {
531         int n;
532         float fcolor[8];
533         entity_render_t *ent;
534         model_t *model;
535         vec3_t org;
536         if (r_refdef.worldmodel == NULL || !r_refdef.worldmodel->brush.data_nodes)
537                 return;
538         fcolor[0] = cr1;
539         fcolor[1] = cg1;
540         fcolor[2] = cb1;
541         fcolor[3] = ca1 * (1.0f / 64.0f);
542         fcolor[4] = cr2 - cr1;
543         fcolor[5] = cg2 - cg1;
544         fcolor[6] = cb2 - cb1;
545         fcolor[7] = (ca2 - ca1) * (1.0f / 64.0f);
546
547         R_StainNode(r_refdef.worldmodel->brush.data_nodes + r_refdef.worldmodel->brushq1.hulls[0].firstclipnode, r_refdef.worldmodel, origin, radius, fcolor);
548
549         // look for embedded bmodels
550         for (n = 0;n < cl_num_brushmodel_entities;n++)
551         {
552                 ent = cl_brushmodel_entities[n];
553                 model = ent->model;
554                 if (model && model->name[0] == '*')
555                 {
556                         Mod_CheckLoaded(model);
557                         if (model->brush.data_nodes)
558                         {
559                                 Matrix4x4_Transform(&ent->inversematrix, origin, org);
560                                 R_StainNode(model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, model, org, radius, fcolor);
561                         }
562                 }
563         }
564 }
565
566
567 /*
568 =============================================================
569
570         BRUSH MODELS
571
572 =============================================================
573 */
574
575 #ifdef LHREMOVESOON
576 static void RSurf_AddLightmapToVertexColors_Color4f(const int *lightmapoffsets, float *c, int numverts, const qbyte *samples, int size3, const qbyte *styles)
577 {
578         int i;
579         float scale;
580         const qbyte *lm;
581         if (styles[0] != 255)
582         {
583                 for (i = 0;i < numverts;i++, c += 4)
584                 {
585                         lm = samples + lightmapoffsets[i];
586                         scale = d_lightstylevalue[styles[0]] * (1.0f / 32768.0f);
587                         VectorMA(c, scale, lm, c);
588                         if (styles[1] != 255)
589                         {
590                                 lm += size3;
591                                 scale = d_lightstylevalue[styles[1]] * (1.0f / 32768.0f);
592                                 VectorMA(c, scale, lm, c);
593                                 if (styles[2] != 255)
594                                 {
595                                         lm += size3;
596                                         scale = d_lightstylevalue[styles[2]] * (1.0f / 32768.0f);
597                                         VectorMA(c, scale, lm, c);
598                                         if (styles[3] != 255)
599                                         {
600                                                 lm += size3;
601                                                 scale = d_lightstylevalue[styles[3]] * (1.0f / 32768.0f);
602                                                 VectorMA(c, scale, lm, c);
603                                         }
604                                 }
605                         }
606                 }
607         }
608 }
609 #endif
610
611 #ifdef LHREMOVESOON
612 static void RSurf_FogColors_Vertex3f_Color4f(const float *v, float *c, float colorscale, int numverts, const float *modelorg)
613 {
614         int i;
615         float diff[3], f;
616         if (fogenabled)
617         {
618                 for (i = 0;i < numverts;i++, v += 3, c += 4)
619                 {
620                         VectorSubtract(v, modelorg, diff);
621                         f = colorscale * (1 - exp(fogdensity/DotProduct(diff, diff)));
622                         VectorScale(c, f, c);
623                 }
624         }
625         else if (colorscale != 1)
626                 for (i = 0;i < numverts;i++, c += 4)
627                         VectorScale(c, colorscale, c);
628 }
629 #endif
630
631 #ifdef LHREMOVESOON
632 static void RSurf_FoggedColors_Vertex3f_Color4f(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg)
633 {
634         int i;
635         float diff[3], f;
636         r *= colorscale;
637         g *= colorscale;
638         b *= colorscale;
639         if (fogenabled)
640         {
641                 for (i = 0;i < numverts;i++, v += 3, c += 4)
642                 {
643                         VectorSubtract(v, modelorg, diff);
644                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
645                         c[0] = r * f;
646                         c[1] = g * f;
647                         c[2] = b * f;
648                         c[3] = a;
649                 }
650         }
651         else
652         {
653                 for (i = 0;i < numverts;i++, c += 4)
654                 {
655                         c[0] = r;
656                         c[1] = g;
657                         c[2] = b;
658                         c[3] = a;
659                 }
660         }
661 }
662 #endif
663
664 #ifdef LHREMOVESOON
665 static void RSurf_FogPassColors_Vertex3f_Color4f(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg)
666 {
667         int i;
668         float diff[3], f;
669         r *= colorscale;
670         g *= colorscale;
671         b *= colorscale;
672         for (i = 0;i < numverts;i++, v += 3, c += 4)
673         {
674                 VectorSubtract(v, modelorg, diff);
675                 f = exp(fogdensity/DotProduct(diff, diff));
676                 c[0] = r;
677                 c[1] = g;
678                 c[2] = b;
679                 c[3] = a * f;
680         }
681 }
682 #endif
683
684 #ifdef LHREMOVESOON
685 static int RSurf_LightSeparate_Vertex3f_Color4f(const matrix4x4_t *matrix, const int *dlightbits, int numverts, const float *vert, float *color, float scale)
686 {
687         float f;
688         const float *v;
689         float *c;
690         int i, l, lit = false;
691         const dlight_t *light;
692         vec3_t lightorigin;
693         for (l = 0;l < r_numdlights;l++)
694         {
695                 if (dlightbits[l >> 5] & (1 << (l & 31)))
696                 {
697                         light = &r_dlight[l];
698                         Matrix4x4_Transform(matrix, light->origin, lightorigin);
699                         for (i = 0, v = vert, c = color;i < numverts;i++, v += 3, c += 4)
700                         {
701                                 f = VectorDistance2(v, lightorigin) + LIGHTOFFSET;
702                                 if (f < light->rtlight.lightmap_cullradius2)
703                                 {
704                                         f = ((1.0f / f) - light->rtlight.lightmap_subtract) * scale;
705                                         VectorMA(c, f, light->rtlight.lightmap_light, c);
706                                         lit = true;
707                                 }
708                         }
709                 }
710         }
711         return lit;
712 }
713 #endif
714
715 static float *RSurf_GetVertexPointer(const entity_render_t *ent, const msurface_t *surface)
716 {
717         if (surface->texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
718         {
719                 texture_t *texture = surface->texture;
720                 int i, j;
721                 float center[3], center2[3], forward[3], right[3], up[3], v[4][3];
722                 matrix4x4_t matrix1, imatrix1;
723                 R_Mesh_Matrix(&r_identitymatrix);
724                 // a single autosprite surface can contain multiple sprites...
725                 for (j = 0;j < surface->mesh.num_vertices - 3;j += 4)
726                 {
727                         VectorClear(center);
728                         for (i = 0;i < 4;i++)
729                                 VectorAdd(center, surface->mesh.data_vertex3f + (j+i) * 3, center);
730                         VectorScale(center, 0.25f, center);
731                         Matrix4x4_Transform(&ent->matrix, center, center2);
732                         // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out?
733                         Matrix4x4_FromVectors(&matrix1, surface->mesh.data_normal3f + j*3, surface->mesh.data_svector3f + j*3, surface->mesh.data_tvector3f + j*3, center);
734                         Matrix4x4_Invert_Simple(&imatrix1, &matrix1);
735                         for (i = 0;i < 4;i++)
736                                 Matrix4x4_Transform(&imatrix1, surface->mesh.data_vertex3f + (j+i)*3, v[i]);
737                         if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2)
738                         {
739                                 forward[0] = r_vieworigin[0] - center2[0];
740                                 forward[1] = r_vieworigin[1] - center2[1];
741                                 forward[2] = 0;
742                                 VectorNormalize(forward);
743                                 right[0] = forward[1];
744                                 right[1] = -forward[0];
745                                 right[2] = 0;
746                                 up[0] = 0;
747                                 up[1] = 0;
748                                 up[2] = 1;
749                         }
750                         else
751                         {
752                                 VectorCopy(r_viewforward, forward);
753                                 VectorCopy(r_viewright, right);
754                                 VectorCopy(r_viewup, up);
755                         }
756                         for (i = 0;i < 4;i++)
757                                 VectorMAMAMAM(1, center2, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (i+j) * 3);
758                 }
759                 return varray_vertex3f;
760         }
761         else
762                 return surface->mesh.data_vertex3f;
763 }
764
765 void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
766 {
767         // we don't need to set currentframe if t->animated is false because
768         // it was already set up by the texture loader for non-animating
769         if (t->animated)
770         {
771                 t->currentframe = t->anim_frames[ent->frame != 0][(t->anim_total[ent->frame != 0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[ent->frame != 0]) : 0];
772                 t = t->currentframe;
773         }
774         t->currentmaterialflags = t->basematerialflags;
775         t->currentalpha = ent->alpha;
776         if (t->basematerialflags & MATERIALFLAG_WATERALPHA)
777                 t->currentalpha *= r_wateralpha.value;
778         if (!(ent->flags & RENDER_LIGHT))
779                 t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
780         if (ent->effects & EF_ADDITIVE)
781                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT;
782         else if (t->currentalpha < 1)
783                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
784 }
785
786 matrix4x4_t r_surf_waterscrollmatrix;
787
788 void R_UpdateAllTextureInfo(entity_render_t *ent)
789 {
790         int i;
791         Matrix4x4_CreateTranslate(&r_surf_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
792         if (ent->model)
793                 for (i = 0;i < ent->model->brush.num_textures;i++)
794                         R_UpdateTextureInfo(ent, ent->model->brush.data_textures + i);
795 }
796
797 static void R_DrawSurfaceList(const entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
798 {
799         int i;
800         int texturesurfaceindex;
801         const float *v;
802         float *c;
803         float diff[3];
804         float f, r, g, b, a, base, colorscale;
805         const msurface_t *surface;
806         qboolean dolightmap;
807         qboolean dobase;
808         qboolean doambient;
809         qboolean dodetail;
810         qboolean doglow;
811         qboolean dofogpass;
812         qboolean fogallpasses;
813         qboolean waterscrolling;
814         rmeshstate_t m;
815         texture = texture->currentframe;
816         if (texture->currentmaterialflags & MATERIALFLAG_NODRAW)
817                 return;
818         c_faces += texturenumsurfaces;
819         // gl_lightmaps debugging mode skips normal texturing
820         if (gl_lightmaps.integer)
821         {
822                 GL_BlendFunc(GL_ONE, GL_ZERO);
823                 GL_DepthMask(true);
824                 GL_DepthTest(true);
825                 qglDisable(GL_CULL_FACE);
826                 GL_Color(1, 1, 1, 1);
827                 memset(&m, 0, sizeof(m));
828                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
829                 {
830                         surface = texturesurfacelist[texturesurfaceindex];
831                         m.tex[0] = R_GetTexture(surface->lightmaptexture);
832                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
833                         if (surface->lightmaptexture)
834                         {
835                                 GL_Color(1, 1, 1, 1);
836                                 m.pointer_color = NULL;
837                         }
838                         else
839                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
840                         m.pointer_vertex = surface->mesh.data_vertex3f;
841                         R_Mesh_State(&m);
842                         GL_LockArrays(0, surface->mesh.num_vertices);
843                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
844                         GL_LockArrays(0, 0);
845                 }
846                 qglEnable(GL_CULL_FACE);
847                 return;
848         }
849         GL_DepthTest(!(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
850         GL_DepthMask(!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT));
851         if (texture->currentmaterialflags & MATERIALFLAG_ADD)
852                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
853         else if (texture->currentmaterialflags & MATERIALFLAG_ALPHA)
854                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
855         else
856                 GL_BlendFunc(GL_ONE, GL_ZERO);
857         // water waterscrolling in texture matrix
858         waterscrolling = (texture->currentmaterialflags & MATERIALFLAG_WATER) && r_waterscroll.value != 0;
859         if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
860                 qglDisable(GL_CULL_FACE);
861         if (texture->currentmaterialflags & MATERIALFLAG_SKY)
862         {
863                 if (skyrendernow)
864                 {
865                         skyrendernow = false;
866                         if (skyrendermasked)
867                                 R_Sky();
868                 }
869                 // LordHavoc: HalfLife maps have freaky skypolys...
870                 if (!ent->model->brush.ishlbsp)
871                 {
872                         R_Mesh_Matrix(&ent->matrix);
873                         GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1);
874                         if (skyrendermasked)
875                         {
876                                 // depth-only (masking)
877                                 GL_ColorMask(0,0,0,0);
878                                 // just to make sure that braindead drivers don't draw anything
879                                 // despite that colormask...
880                                 GL_BlendFunc(GL_ZERO, GL_ONE);
881                         }
882                         else
883                         {
884                                 // fog sky
885                                 GL_BlendFunc(GL_ONE, GL_ZERO);
886                         }
887                         GL_DepthMask(true);
888                         GL_DepthTest(true);
889                         memset(&m, 0, sizeof(m));
890                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
891                         {
892                                 surface = texturesurfacelist[texturesurfaceindex];
893                                 m.pointer_vertex = surface->mesh.data_vertex3f;
894                                 R_Mesh_State(&m);
895                                 GL_LockArrays(0, surface->mesh.num_vertices);
896                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
897                                 GL_LockArrays(0, 0);
898                         }
899                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
900                 }
901         }
902         else if ((texture->currentmaterialflags & MATERIALFLAG_WATER) && r_watershader.value && gl_textureshader && !texture->skin.glow && !fogenabled && ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1)
903         {
904                 // NVIDIA Geforce3 distortion texture shader on water
905                 float args[4] = {0.05f,0,0,0.04f};
906                 memset(&m, 0, sizeof(m));
907                 m.tex[0] = R_GetTexture(mod_shared_distorttexture[(int)(r_refdef.time * 16)&63]);
908                 m.tex[1] = R_GetTexture(texture->skin.base);
909                 m.texcombinergb[0] = GL_REPLACE;
910                 m.texcombinergb[1] = GL_REPLACE;
911                 Matrix4x4_CreateFromQuakeEntity(&m.texmatrix[0], 0, 0, 0, 0, 0, 0, r_watershader.value);
912                 m.texmatrix[1] = r_surf_waterscrollmatrix;
913
914                 GL_ActiveTexture(0);
915                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
916                 GL_ActiveTexture(1);
917                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_OFFSET_TEXTURE_2D_NV);
918                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);
919                 qglTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, &args[0]);
920                 qglEnable(GL_TEXTURE_SHADER_NV);
921
922                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
923                 {
924                         surface = texturesurfacelist[texturesurfaceindex];
925                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
926                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
927                         m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
928                         R_Mesh_State(&m);
929                         GL_LockArrays(0, surface->mesh.num_vertices);
930                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
931                         GL_LockArrays(0, 0);
932                 }
933
934                 qglDisable(GL_TEXTURE_SHADER_NV);
935                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
936                 GL_ActiveTexture(0);
937         }
938         else if (texture->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
939         {
940                 // normal surface (wall or water)
941                 dobase = true;
942                 dolightmap = !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT);
943                 doambient = r_ambient.value >= (1/64.0f);
944                 dodetail = texture->skin.detail != NULL && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
945                 doglow = texture->skin.glow != NULL;
946                 dofogpass = fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_ADD);
947                 fogallpasses = fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
948                 if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
949                 {
950                         if (dobase && dolightmap && gl_combine.integer)
951                         {
952                                 dobase = false;
953                                 memset(&m, 0, sizeof(m));
954                                 m.tex[1] = R_GetTexture(texture->skin.base);
955                                 if (waterscrolling)
956                                         m.texmatrix[1] = r_surf_waterscrollmatrix;
957                                 m.texrgbscale[1] = 2;
958                                 m.pointer_color = varray_color4f;
959                                 colorscale = 1;
960                                 r = ent->colormod[0] * colorscale;
961                                 g = ent->colormod[1] * colorscale;
962                                 b = ent->colormod[2] * colorscale;
963                                 a = texture->currentalpha;
964                                 base = r_ambient.value * (1.0f / 64.0f);
965                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
966                                 {
967                                         surface = texturesurfacelist[texturesurfaceindex];
968                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
969                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
970                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
971                                         if (surface->lightmaptexture)
972                                         {
973                                                 m.tex[0] = R_GetTexture(surface->lightmaptexture);
974                                                 if (fogallpasses)
975                                                 {
976                                                         m.pointer_color = varray_color4f;
977                                                         for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
978                                                         {
979                                                                 VectorSubtract(v, modelorg, diff);
980                                                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
981                                                                 c[0] = f * r;
982                                                                 c[1] = f * g;
983                                                                 c[2] = f * b;
984                                                                 c[3] = a;
985                                                         }
986                                                 }
987                                                 else
988                                                 {
989                                                         m.pointer_color = NULL;
990                                                         GL_Color(r, g, b, a);
991                                                 }
992                                         }
993                                         else
994                                         {
995                                                 m.tex[0] = R_GetTexture(r_texture_white);
996                                                 m.pointer_color = varray_color4f;
997 #ifdef LHREMOVESOON
998                                                 if (surface->styles[0] != 255 || surface->dlightframe == r_framecount)
999 #else
1000                                                 if (surface->styles[0] != 255)
1001 #endif
1002                                                 {
1003                                                         for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1004                                                         {
1005                                                                 c[0] = 0;
1006                                                                 c[1] = 0;
1007                                                                 c[2] = 0;
1008                                                                 if (surface->styles[0] != 255)
1009                                                                 {
1010                                                                         if (surface->mesh.data_lightmapcolor4f)
1011                                                                         {
1012                                                                                 float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 128.0f);
1013                                                                                 VectorMA(c, scale, surface->mesh.data_lightmapcolor4f + i*4, c);
1014                                                                         }
1015                                                                         else if (surface->mesh.data_lightmapoffsets)
1016                                                                         {
1017                                                                                 const qbyte *lm = surface->samples + surface->mesh.data_lightmapoffsets[i];
1018                                                                                 float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 32768.0f);
1019                                                                                 VectorMA(c, scale, lm, c);
1020                                                                                 if (surface->styles[1] != 255)
1021                                                                                 {
1022                                                                                         int size3 = ((surface->extents[0]>>4)+1)*((surface->extents[1]>>4)+1)*3;
1023                                                                                         lm += size3;
1024                                                                                         scale = d_lightstylevalue[surface->styles[1]] * (1.0f / 32768.0f);
1025                                                                                         VectorMA(c, scale, lm, c);
1026                                                                                         if (surface->styles[2] != 255)
1027                                                                                         {
1028                                                                                                 lm += size3;
1029                                                                                                 scale = d_lightstylevalue[surface->styles[2]] * (1.0f / 32768.0f);
1030                                                                                                 VectorMA(c, scale, lm, c);
1031                                                                                                 if (surface->styles[3] != 255)
1032                                                                                                 {
1033                                                                                                         lm += size3;
1034                                                                                                         scale = d_lightstylevalue[surface->styles[3]] * (1.0f / 32768.0f);
1035                                                                                                         VectorMA(c, scale, lm, c);
1036                                                                                                 }
1037                                                                                         }
1038                                                                                 }
1039                                                                         }
1040                                                                 }
1041 #ifdef LHREMOVESOON
1042                                                                 if (surface->dlightframe == r_framecount)
1043                                                                 {
1044                                                                         int l;
1045                                                                         float worldvertex[3];
1046                                                                         // TODO: make this work with autosprite which uses identitymatrix
1047                                                                         Matrix4x4_Transform(&ent->matrix, v, worldvertex);
1048                                                                         for (l = 0;l < r_numdlights;l++)
1049                                                                         {
1050                                                                                 if (surface->dlightbits[l >> 5] & (1 << (l & 31)))
1051                                                                                 {
1052                                                                                         float f2;
1053                                                                                         dlight_t *light = &r_dlight[l];
1054                                                                                         f2 = VectorDistance2(worldvertex, light->origin) + LIGHTOFFSET;
1055                                                                                         if (f2 < light->rtlight.lightmap_cullradius2)
1056                                                                                         {
1057                                                                                                 f2 = (1.0f / f2) - light->rtlight.lightmap_subtract;
1058                                                                                                 VectorMA(c, f2, light->rtlight.lightmap_light, c);
1059                                                                                         }
1060                                                                                 }
1061                                                                         }
1062                                                                 }
1063 #endif
1064                                                                 c[0] *= r;
1065                                                                 c[1] *= g;
1066                                                                 c[2] *= b;
1067                                                                 if (fogallpasses)
1068                                                                 {
1069                                                                         VectorSubtract(v, modelorg, diff);
1070                                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
1071                                                                         VectorScale(c, f, c);
1072                                                                 }
1073                                                                 if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1074                                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1075                                                                 else
1076                                                                         c[3] = a;
1077                                                         }
1078                                                 }
1079                                                 else
1080                                                 {
1081                                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1082                                                         {
1083                                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1084                                                                 {
1085                                                                         c[0] = 0;
1086                                                                         c[1] = 0;
1087                                                                         c[2] = 0;
1088                                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1089                                                                 }
1090                                                         }
1091                                                         else
1092                                                         {
1093                                                                 m.pointer_color = NULL;
1094                                                                 GL_Color(0, 0, 0, a);
1095                                                         }
1096                                                 }
1097                                         }
1098                                         R_Mesh_State(&m);
1099                                         GL_LockArrays(0, surface->mesh.num_vertices);
1100                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1101                                         GL_LockArrays(0, 0);
1102                                 }
1103                         }
1104                         if (dobase)
1105                         {
1106                                 dobase = false;
1107                                 memset(&m, 0, sizeof(m));
1108                                 m.tex[0] = R_GetTexture(texture->skin.base);
1109                                 if (waterscrolling)
1110                                         m.texmatrix[0] = r_surf_waterscrollmatrix;
1111                                 m.texmatrix[0] = r_surf_waterscrollmatrix;
1112                                 m.pointer_color = varray_color4f;
1113                                 colorscale = 1;
1114                                 if (gl_combine.integer)
1115                                 {
1116                                         m.texrgbscale[0] = 4;
1117                                         colorscale *= 0.25f;
1118                                 }
1119                                 r = ent->colormod[0] * colorscale;
1120                                 g = ent->colormod[1] * colorscale;
1121                                 b = ent->colormod[2] * colorscale;
1122                                 a = texture->currentalpha;
1123                                 if (dolightmap)
1124                                 {
1125                                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1126                                         {
1127                                                 surface = texturesurfacelist[texturesurfaceindex];
1128                                                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1129                                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1130                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1131                                                 {
1132                                                         c[0] = 0;
1133                                                         c[1] = 0;
1134                                                         c[2] = 0;
1135                                                         if (surface->styles[0] != 255)
1136                                                         {
1137                                                                 if (surface->mesh.data_lightmapcolor4f)
1138                                                                 {
1139                                                                         float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 128.0f);
1140                                                                         VectorMA(c, scale, surface->mesh.data_lightmapcolor4f + i*4, c);
1141                                                                 }
1142                                                                 else if (surface->mesh.data_lightmapoffsets)
1143                                                                 {
1144                                                                         const qbyte *lm = surface->samples + surface->mesh.data_lightmapoffsets[i];
1145                                                                         float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 32768.0f);
1146                                                                         VectorMA(c, scale, lm, c);
1147                                                                         if (surface->styles[1] != 255)
1148                                                                         {
1149                                                                                 int size3 = ((surface->extents[0]>>4)+1)*((surface->extents[1]>>4)+1)*3;
1150                                                                                 lm += size3;
1151                                                                                 scale = d_lightstylevalue[surface->styles[1]] * (1.0f / 32768.0f);
1152                                                                                 VectorMA(c, scale, lm, c);
1153                                                                                 if (surface->styles[2] != 255)
1154                                                                                 {
1155                                                                                         lm += size3;
1156                                                                                         scale = d_lightstylevalue[surface->styles[2]] * (1.0f / 32768.0f);
1157                                                                                         VectorMA(c, scale, lm, c);
1158                                                                                         if (surface->styles[3] != 255)
1159                                                                                         {
1160                                                                                                 lm += size3;
1161                                                                                                 scale = d_lightstylevalue[surface->styles[3]] * (1.0f / 32768.0f);
1162                                                                                                 VectorMA(c, scale, lm, c);
1163                                                                                         }
1164                                                                                 }
1165                                                                         }
1166                                                                 }
1167                                                         }
1168 #ifdef LHREMOVESOON
1169                                                         if (surface->dlightframe == r_framecount)
1170                                                         {
1171                                                                 // TODO: make this work with autosprite which uses identitymatrix
1172                                                                 Matrix4x4_Transform(&ent->matrix, v, worldvertex);
1173                                                                 for (l = 0;l < r_numdlights;l++)
1174                                                                 {
1175                                                                         if (surface->dlightbits[l >> 5] & (1 << (l & 31)))
1176                                                                         {
1177                                                                                 float f2;
1178                                                                                 dlight_t *light = &r_dlight[l];
1179                                                                                 f2 = VectorDistance2(worldvertex, light->origin) + LIGHTOFFSET;
1180                                                                                 if (f2 < light->rtlight.lightmap_cullradius2)
1181                                                                                 {
1182                                                                                         f2 = (1.0f / f2) - light->rtlight.lightmap_subtract;
1183                                                                                         VectorMA(c, f2, light->rtlight.lightmap_light, c);
1184                                                                                 }
1185                                                                         }
1186                                                                 }
1187                                                         }
1188 #endif
1189                                                         c[0] *= r;
1190                                                         c[1] *= g;
1191                                                         c[2] *= b;
1192                                                         if (fogallpasses)
1193                                                         {
1194                                                                 VectorSubtract(v, modelorg, diff);
1195                                                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
1196                                                                 VectorScale(c, f, c);
1197                                                         }
1198                                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1199                                                                 c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1200                                                         else
1201                                                                 c[3] = a;
1202                                                 }
1203                                                 R_Mesh_State(&m);
1204                                                 GL_LockArrays(0, surface->mesh.num_vertices);
1205                                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1206                                                 GL_LockArrays(0, 0);
1207                                         }
1208                                 }
1209                                 else
1210                                 {
1211                                         if (fogallpasses)
1212                                         {
1213                                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1214                                                 {
1215                                                         surface = texturesurfacelist[texturesurfaceindex];
1216                                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1217                                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1218                                                         if (m.tex[1])
1219                                                                 m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
1220                                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1221                                                         {
1222                                                                 m.pointer_color = varray_color4f;
1223                                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1224                                                                 {
1225                                                                         VectorSubtract(v, modelorg, diff);
1226                                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
1227                                                                         c[0] = r * f;
1228                                                                         c[1] = g * f;
1229                                                                         c[2] = b * f;
1230                                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1231                                                                 }
1232                                                         }
1233                                                         else
1234                                                         {
1235                                                                 m.pointer_color = varray_color4f;
1236                                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1237                                                                 {
1238                                                                         VectorSubtract(v, modelorg, diff);
1239                                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
1240                                                                         c[0] = r * f;
1241                                                                         c[1] = g * f;
1242                                                                         c[2] = b * f;
1243                                                                         c[3] = a;
1244                                                                 }
1245                                                         }
1246                                                         R_Mesh_State(&m);
1247                                                         GL_LockArrays(0, surface->mesh.num_vertices);
1248                                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1249                                                         GL_LockArrays(0, 0);
1250                                                 }
1251                                         }
1252                                         else
1253                                         {
1254                                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1255                                                 {
1256                                                         surface = texturesurfacelist[texturesurfaceindex];
1257                                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1258                                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1259                                                         if (m.tex[1])
1260                                                                 m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
1261                                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1262                                                         {
1263                                                                 m.pointer_color = varray_color4f;
1264                                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1265                                                                 {
1266                                                                         c[0] = r;
1267                                                                         c[1] = g;
1268                                                                         c[2] = b;
1269                                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1270                                                                 }
1271                                                         }
1272                                                         else
1273                                                         {
1274                                                                 m.pointer_color = NULL;
1275                                                                 GL_Color(r, g, b, a);
1276                                                         }
1277                                                         R_Mesh_State(&m);
1278                                                         GL_LockArrays(0, surface->mesh.num_vertices);
1279                                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1280                                                         GL_LockArrays(0, 0);
1281                                                 }
1282                                         }
1283                                 }
1284                         }
1285                 }
1286                 else
1287                 {
1288                         if (!dolightmap && dobase)
1289                         {
1290                                 dolightmap = false;
1291                                 dobase = false;
1292                                 GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], 1);
1293                                 memset(&m, 0, sizeof(m));
1294                                 m.tex[0] = R_GetTexture(texture->skin.base);
1295                                 if (waterscrolling)
1296                                         m.texmatrix[0] = r_surf_waterscrollmatrix;
1297                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1298                                 {
1299                                         surface = texturesurfacelist[texturesurfaceindex];
1300                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1301                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1302                                         R_Mesh_State(&m);
1303                                         GL_LockArrays(0, surface->mesh.num_vertices);
1304                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1305                                         GL_LockArrays(0, 0);
1306                                 }
1307                         }
1308                         if (r_lightmapintensity <= 0 && dolightmap && dobase)
1309                         {
1310                                 dolightmap = false;
1311                                 dobase = false;
1312                                 GL_Color(0, 0, 0, 1);
1313                                 memset(&m, 0, sizeof(m));
1314                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1315                                 {
1316                                         surface = texturesurfacelist[texturesurfaceindex];
1317                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1318                                         R_Mesh_State(&m);
1319                                         GL_LockArrays(0, surface->mesh.num_vertices);
1320                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1321                                         GL_LockArrays(0, 0);
1322                                 }
1323                         }
1324                         if (r_textureunits.integer >= 2 && gl_combine.integer && dolightmap && dobase)
1325                         {
1326                                 // dualtexture combine
1327                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1328                                 GL_DepthMask(true);
1329                                 dolightmap = false;
1330                                 dobase = false;
1331                                 memset(&m, 0, sizeof(m));
1332                                 m.tex[1] = R_GetTexture(texture->skin.base);
1333                                 if (waterscrolling)
1334                                         m.texmatrix[1] = r_surf_waterscrollmatrix;
1335                                 m.texrgbscale[1] = 2;
1336                                 r = ent->colormod[0] * r_lightmapintensity;
1337                                 g = ent->colormod[1] * r_lightmapintensity;
1338                                 b = ent->colormod[2] * r_lightmapintensity;
1339                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1340                                 {
1341                                         surface = texturesurfacelist[texturesurfaceindex];
1342                                         memset(&m, 0, sizeof(m));
1343                                         m.tex[1] = R_GetTexture(texture->skin.base);
1344                                         if (waterscrolling)
1345                                                 m.texmatrix[1] = r_surf_waterscrollmatrix;
1346                                         m.texrgbscale[1] = 2;
1347                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1348                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
1349                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
1350                                         if (surface->lightmaptexture)
1351                                         {
1352                                                 m.tex[0] = R_GetTexture(surface->lightmaptexture);
1353                                                 m.pointer_color = NULL;
1354                                                 GL_Color(r, g, b, 1);
1355                                         }
1356                                         else if (r == 1 && g == 1 && b == 1)
1357                                         {
1358                                                 m.tex[0] = R_GetTexture(r_texture_white);
1359                                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
1360                                         }
1361                                         else
1362                                         {
1363                                                 m.tex[0] = R_GetTexture(r_texture_white);
1364                                                 m.pointer_color = varray_color4f;
1365                                                 for (i = 0;i < surface->mesh.num_vertices;i++)
1366                                                 {
1367                                                         varray_color4f[i*4+0] = surface->mesh.data_lightmapcolor4f[i*4+0] * r;
1368                                                         varray_color4f[i*4+1] = surface->mesh.data_lightmapcolor4f[i*4+1] * g;
1369                                                         varray_color4f[i*4+2] = surface->mesh.data_lightmapcolor4f[i*4+2] * b;
1370                                                         varray_color4f[i*4+3] = surface->mesh.data_lightmapcolor4f[i*4+3];
1371                                                 }
1372                                         }
1373                                         R_Mesh_State(&m);
1374                                         GL_LockArrays(0, surface->mesh.num_vertices);
1375                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1376                                         GL_LockArrays(0, 0);
1377                                 }
1378                         }
1379                         // single texture
1380                         if (dolightmap)
1381                         {
1382                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1383                                 GL_DepthMask(true);
1384                                 GL_Color(1, 1, 1, 1);
1385                                 memset(&m, 0, sizeof(m));
1386                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1387                                 {
1388                                         surface = texturesurfacelist[texturesurfaceindex];
1389                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1390                                         m.tex[0] = R_GetTexture(surface->lightmaptexture);
1391                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
1392                                         if (surface->lightmaptexture)
1393                                                 m.pointer_color = NULL;
1394                                         else
1395                                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
1396                                         R_Mesh_State(&m);
1397                                         GL_LockArrays(0, surface->mesh.num_vertices);
1398                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1399                                         GL_LockArrays(0, 0);
1400                                 }
1401                         }
1402                         if (dobase)
1403                         {
1404                                 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1405                                 GL_DepthMask(false);
1406                                 GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
1407                                 memset(&m, 0, sizeof(m));
1408                                 m.tex[0] = R_GetTexture(texture->skin.base);
1409                                 if (waterscrolling)
1410                                         m.texmatrix[0] = r_surf_waterscrollmatrix;
1411                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1412                                 {
1413                                         surface = texturesurfacelist[texturesurfaceindex];
1414                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1415                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1416                                         R_Mesh_State(&m);
1417                                         GL_LockArrays(0, surface->mesh.num_vertices);
1418                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1419                                         GL_LockArrays(0, 0);
1420                                 }
1421                         }
1422                 }
1423                 if (doambient)
1424                 {
1425                         doambient = false;
1426                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1427                         GL_DepthMask(false);
1428                         memset(&m, 0, sizeof(m));
1429                         m.tex[0] = R_GetTexture(texture->skin.base);
1430                         if (waterscrolling)
1431                                 m.texmatrix[0] = r_surf_waterscrollmatrix;
1432                         m.pointer_color = varray_color4f;
1433                         colorscale = 1;
1434                         if (gl_combine.integer)
1435                         {
1436                                 m.texrgbscale[0] = 4;
1437                                 colorscale *= 0.25f;
1438                         }
1439                         base = r_ambient.value * (1.0f / 64.0f);
1440                         r = ent->colormod[0] * colorscale * base;
1441                         g = ent->colormod[1] * colorscale * base;
1442                         b = ent->colormod[2] * colorscale * base;
1443                         a = texture->currentalpha;
1444                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1445                         {
1446                                 surface = texturesurfacelist[texturesurfaceindex];
1447                                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1448                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1449                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1450                                 {
1451                                         c[0] = r;
1452                                         c[1] = g;
1453                                         c[2] = b;
1454                                         if (fogallpasses)
1455                                         {
1456                                                 VectorSubtract(v, modelorg, diff);
1457                                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
1458                                                 VectorScale(c, f, c);
1459                                         }
1460                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1461                                                 c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1462                                         else
1463                                                 c[3] = a;
1464                                 }
1465                                 R_Mesh_State(&m);
1466                                 GL_LockArrays(0, surface->mesh.num_vertices);
1467                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1468                                 GL_LockArrays(0, 0);
1469                         }
1470                 }
1471                 // marklights based vertex dlight rendering...  evil and broken
1472 #if 0
1473                 GL_BlendFunc(GL_ONE, GL_ONE);
1474                 GL_DepthMask(false);
1475                 memset(&m, 0, sizeof(m));
1476                 m.tex[0] = R_GetTexture(texture->skin.base);
1477                 if (waterscrolling)
1478                         m.texmatrix[0] = r_surf_waterscrollmatrix;
1479                 m.pointer_color = varray_color4f;
1480                 r = ent->colormod[0] * r_lightmapintensity;
1481                 g = ent->colormod[1] * r_lightmapintensity;
1482                 b = ent->colormod[2] * r_lightmapintensity;
1483                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1484                 {
1485                         qboolean lit;
1486                         surface = texturesurfacelist[texturesurfaceindex];
1487                         if (surface->dlightframe != r_framecount)
1488                                 continue;
1489                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1490                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1491                         lit = false;
1492                         for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1493                         {
1494                                 c[0] = 0;
1495                                 c[1] = 0;
1496                                 c[2] = 0;
1497                                 c[3] = 1;
1498                                 // TODO: make this work with autosprite which uses identitymatrix or change autosprite
1499                                 Matrix4x4_Transform(&ent->matrix, v, worldvertex);
1500                                 for (l = 0;l < r_numdlights;l++)
1501                                 {
1502                                         if (surface->dlightbits[l >> 5] & (1 << (l & 31)))
1503                                         {
1504                                                 float f2;
1505                                                 dlight_t *light = &r_dlight[l];
1506                                                 f2 = VectorDistance2(worldvertex, light->origin) + LIGHTOFFSET;
1507                                                 if (f2 < light->rtlight.lightmap_cullradius2)
1508                                                 {
1509                                                         f2 = (1.0f / f2) - light->rtlight.lightmap_subtract;
1510                                                         VectorMA(c, f2, light->rtlight.lightmap_light, c);
1511                                                         lit = true;
1512                                                 }
1513                                         }
1514                                 }
1515                                 c[0] *= r;
1516                                 c[1] *= g;
1517                                 c[2] *= b;
1518                                 if (fogallpasses)
1519                                 {
1520                                         VectorSubtract(v, modelorg, diff);
1521                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
1522                                         VectorScale(c, f, c);
1523                                 }
1524                                 if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1525                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1526                                 else
1527                                         c[3] = a;
1528                         }
1529                         if (!lit)
1530                                 continue;
1531                         R_Mesh_State(&m);
1532                         GL_LockArrays(0, surface->mesh.num_vertices);
1533                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1534                         GL_LockArrays(0, 0);
1535                 }
1536 #endif
1537                 if (dodetail)
1538                 {
1539                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1540                         GL_DepthMask(false);
1541                         GL_Color(1, 1, 1, 1);
1542                         memset(&m, 0, sizeof(m));
1543                         m.tex[0] = R_GetTexture(texture->skin.detail);
1544                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1545                         {
1546                                 surface = texturesurfacelist[texturesurfaceindex];
1547                                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1548                                 m.pointer_texcoord[0] = surface->mesh.data_texcoorddetail2f;
1549                                 R_Mesh_State(&m);
1550                                 GL_LockArrays(0, surface->mesh.num_vertices);
1551                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1552                                 GL_LockArrays(0, 0);
1553                         }
1554                 }
1555                 if (doglow)
1556                 {
1557                         // if glow was not already done using multitexture, do it now.
1558                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1559                         GL_DepthMask(false);
1560                         memset(&m, 0, sizeof(m));
1561                         m.tex[0] = R_GetTexture(texture->skin.glow);
1562                         if (waterscrolling)
1563                                 m.texmatrix[0] = r_surf_waterscrollmatrix;
1564                         m.pointer_color = varray_color4f;
1565                         colorscale = 1;
1566                         r = ent->colormod[0] * colorscale;
1567                         g = ent->colormod[1] * colorscale;
1568                         b = ent->colormod[2] * colorscale;
1569                         a = texture->currentalpha;
1570                         if (fogallpasses)
1571                         {
1572                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1573                                 {
1574                                         surface = texturesurfacelist[texturesurfaceindex];
1575                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1576                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1577                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1578                                         {
1579                                                 m.pointer_color = varray_color4f;
1580                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1581                                                 {
1582                                                         VectorSubtract(v, modelorg, diff);
1583                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
1584                                                         c[0] = f * r;
1585                                                         c[1] = f * g;
1586                                                         c[2] = f * b;
1587                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1588                                                 }
1589                                         }
1590                                         else
1591                                         {
1592                                                 m.pointer_color = varray_color4f;
1593                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1594                                                 {
1595                                                         VectorSubtract(v, modelorg, diff);
1596                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
1597                                                         c[0] = f * r;
1598                                                         c[1] = f * g;
1599                                                         c[2] = f * b;
1600                                                         c[3] = a;
1601                                                 }
1602                                         }
1603                                         R_Mesh_State(&m);
1604                                         GL_LockArrays(0, surface->mesh.num_vertices);
1605                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1606                                         GL_LockArrays(0, 0);
1607                                 }
1608                         }
1609                         else
1610                         {
1611                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1612                                 {
1613                                         surface = texturesurfacelist[texturesurfaceindex];
1614                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1615                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1616                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1617                                         {
1618                                                 m.pointer_color = varray_color4f;
1619                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1620                                                 {
1621                                                         c[0] = r;
1622                                                         c[1] = g;
1623                                                         c[2] = b;
1624                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1625                                                 }
1626                                         }
1627                                         else
1628                                         {
1629                                                 m.pointer_color = NULL;
1630                                                 GL_Color(r, g, b, a);
1631                                         }
1632                                         R_Mesh_State(&m);
1633                                         GL_LockArrays(0, surface->mesh.num_vertices);
1634                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1635                                         GL_LockArrays(0, 0);
1636                                 }
1637                         }
1638                 }
1639                 if (dofogpass)
1640                 {
1641                         // if this is opaque use alpha blend which will darken the earlier
1642                         // passes cheaply.
1643                         //
1644                         // if this is an alpha blended material, all the earlier passes
1645                         // were darkened by fog already, so we only need to add the fog
1646                         // color ontop through the fog mask texture
1647                         //
1648                         // if this is an additive blended material, all the earlier passes
1649                         // were darkened by fog already, and we should not add fog color
1650                         // (because the background was not darkened, there is no fog color
1651                         // that was lost behind it).
1652                         if (!fogallpasses)
1653                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1654                         else
1655                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1656                         GL_DepthMask(false);
1657                         memset(&m, 0, sizeof(m));
1658                         m.tex[0] = R_GetTexture(texture->skin.fog);
1659                         if (waterscrolling)
1660                                 m.texmatrix[0] = r_surf_waterscrollmatrix;
1661                         r = fogcolor[0];
1662                         g = fogcolor[1];
1663                         b = fogcolor[2];
1664                         a = texture->currentalpha;
1665                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1666                         {
1667                                 surface = texturesurfacelist[texturesurfaceindex];
1668                                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1669                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1670                                 m.pointer_color = varray_color4f;
1671                                 //RSurf_FogPassColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg);
1672                                 if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1673                                 {
1674                                         m.pointer_color = varray_color4f;
1675                                         for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1676                                         {
1677                                                 VectorSubtract(v, modelorg, diff);
1678                                                 f = exp(fogdensity/DotProduct(diff, diff));
1679                                                 c[0] = r;
1680                                                 c[1] = g;
1681                                                 c[2] = b;
1682                                                 c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * f * a;
1683                                         }
1684                                 }
1685                                 else
1686                                 {
1687                                         m.pointer_color = varray_color4f;
1688                                         for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1689                                         {
1690                                                 VectorSubtract(v, modelorg, diff);
1691                                                 f = exp(fogdensity/DotProduct(diff, diff));
1692                                                 c[0] = r;
1693                                                 c[1] = g;
1694                                                 c[2] = b;
1695                                                 c[3] = f * a;
1696                                         }
1697                                 }
1698                                 R_Mesh_State(&m);
1699                                 GL_LockArrays(0, surface->mesh.num_vertices);
1700                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1701                                 GL_LockArrays(0, 0);
1702                         }
1703                 }
1704         }
1705         if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1706                 qglEnable(GL_CULL_FACE);
1707 }
1708
1709 static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata2)
1710 {
1711         const entity_render_t *ent = calldata1;
1712         const msurface_t *surface = ent->model->brush.data_surfaces + calldata2;
1713         vec3_t modelorg;
1714         texture_t *texture;
1715 #ifdef LHREMOVESOON
1716         rmeshstate_t m;
1717         float base, colorscale;
1718         float args[4] = {0.05f,0,0,0.04f};
1719         matrix4x4_t scrollmatrix;
1720 #endif
1721
1722         texture = surface->texture;
1723         if (texture->basematerialflags & MATERIALFLAG_SKY)
1724                 return; // transparent sky is too difficult
1725         R_UpdateTextureInfo(ent, texture);
1726
1727         R_Mesh_Matrix(&ent->matrix);
1728         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
1729         R_DrawSurfaceList(ent, texture, 1, &surface, modelorg);
1730 #ifdef LHREMOVESOON
1731         GL_DepthTest(!(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
1732         GL_DepthMask(!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT));
1733         if (texture->currentmaterialflags & MATERIALFLAG_ADD)
1734                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1735         else if (texture->currentmaterialflags & MATERIALFLAG_ALPHA)
1736                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1737         else
1738                 GL_BlendFunc(GL_ONE, GL_ZERO);
1739
1740         // water scrolling in texture matrix
1741         if ((texture->currentmaterialflags & MATERIALFLAG_WATER) && r_waterscroll.value != 0)
1742                 Matrix4x4_CreateTranslate(&scrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
1743         else
1744                 scrollmatrix = r_identitymatrix;
1745
1746         if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1747                 qglDisable(GL_CULL_FACE);
1748         if ((texture->currentmaterialflags & MATERIALFLAG_WATER) && r_watershader.value && gl_textureshader && !texture->skin.glow && !fogenabled && ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1)
1749         {
1750                 // NVIDIA Geforce3 distortion texture shader on water
1751                 GL_Color(1, 1, 1, texture->currentalpha);
1752                 memset(&m, 0, sizeof(m));
1753                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1754                 m.tex[0] = R_GetTexture(mod_shared_distorttexture[(int)(r_refdef.time * 16)&63]);
1755                 m.tex[1] = R_GetTexture(texture->skin.base);
1756                 m.texcombinergb[0] = GL_REPLACE;
1757                 m.texcombinergb[1] = GL_REPLACE;
1758                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1759                 m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
1760                 Matrix4x4_CreateFromQuakeEntity(&m.texmatrix[0], 0, 0, 0, 0, 0, 0, r_watershader.value);
1761                 m.texmatrix[1] = scrollmatrix;
1762                 R_Mesh_State(&m);
1763
1764                 GL_ActiveTexture(0);
1765                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
1766                 GL_ActiveTexture(1);
1767                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_OFFSET_TEXTURE_2D_NV);
1768                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);
1769                 qglTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, &args[0]);
1770                 qglEnable(GL_TEXTURE_SHADER_NV);
1771
1772                 GL_LockArrays(0, surface->mesh.num_vertices);
1773                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1774                 GL_LockArrays(0, 0);
1775
1776                 qglDisable(GL_TEXTURE_SHADER_NV);
1777                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
1778                 GL_ActiveTexture(0);
1779         }
1780         else
1781         {
1782                 int i;
1783                 float r, g, b, a, f, *c, diff[3];
1784                 const float *v;
1785                 qboolean dolightmaptexture;
1786                 qboolean dodetail;
1787                 qboolean doglow;
1788                 dolightmaptexture = surface->lightmaptexture && gl_combine.integer && !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT);
1789                 dodetail = texture->skin.detail != NULL && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
1790                 doglow = texture->skin.glow != NULL;
1791                 // TODO: ideally transparent surface rendering should call
1792                 // R_RenderLighting instead of using vertex dlights
1793                 // (it would need scrolling support added though!)
1794                 if (dolightmaptexture)
1795                 {
1796                         {
1797                                 memset(&m, 0, sizeof(m));
1798                                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1799                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1800                                 m.tex[0] = R_GetTexture(texture->skin.base);
1801                                 m.texmatrix[0] = scrollmatrix;
1802                                 m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
1803                                 m.tex[1] = R_GetTexture(surface->lightmaptexture);
1804                                 m.texrgbscale[1] = 2;
1805                                 m.pointer_color = varray_color4f;
1806                                 if (r_textureunits.integer >= 3 && dodetail)
1807                                 {
1808                                         dodetail = false;
1809                                         m.pointer_texcoord[2] = surface->mesh.data_texcoorddetail2f;
1810                                         m.tex[2] = R_GetTexture(texture->skin.detail);
1811                                         m.texmatrix[2] = scrollmatrix;
1812                                         if (r_textureunits.integer >= 4 && doglow)
1813                                         {
1814                                                 doglow = false;
1815                                                 m.pointer_texcoord[3] = surface->mesh.data_texcoordtexture2f;
1816                                                 m.tex[3] = R_GetTexture(texture->skin.glow);
1817                                                 m.texmatrix[3] = scrollmatrix;
1818                                         }
1819                                 }
1820                                 else if (r_textureunits.integer >= 3 && doglow && !dodetail)
1821                                 {
1822                                         doglow = false;
1823                                         m.pointer_texcoord[2] = surface->mesh.data_texcoordtexture2f;
1824                                         m.tex[2] = R_GetTexture(texture->skin.glow);
1825                                         m.texmatrix[2] = scrollmatrix;
1826                                 }
1827                                 colorscale = 1;
1828                                 r = ent->colormod[0] * colorscale;
1829                                 g = ent->colormod[1] * colorscale;
1830                                 b = ent->colormod[2] * colorscale;
1831                                 a = texture->currentalpha;
1832                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1833                                 {
1834                                         c[0] = r;
1835                                         c[1] = g;
1836                                         c[2] = b;
1837                                         if (fogenabled)
1838                                         {
1839                                                 VectorSubtract(v, modelorg, diff);
1840                                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
1841                                                 VectorScale(c, f, c);
1842                                         }
1843                                         if (surface->mesh.data_lightmapcolor4f)
1844                                                 c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1845                                         else
1846                                                 c[3] = a;
1847                                 }
1848                                 R_Mesh_State(&m);
1849                                 GL_LockArrays(0, surface->mesh.num_vertices);
1850                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1851                                 GL_LockArrays(0, 0);
1852                         }
1853                         if ((r_ambient.value > 0 || surface->dlightframe == r_framecount) && !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
1854                         {
1855                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1856                                 GL_DepthMask(false);
1857                                 memset(&m, 0, sizeof(m));
1858                                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1859                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1860                                 m.tex[0] = R_GetTexture(texture->skin.base);
1861                                 m.texmatrix[0] = scrollmatrix;
1862                                 m.pointer_color = varray_color4f;
1863                                 colorscale = 1;
1864                                 if (gl_combine.integer)
1865                                 {
1866                                         m.texrgbscale[0] = 4;
1867                                         colorscale *= 0.25f;
1868                                 }
1869                                 r = ent->colormod[0] * colorscale;
1870                                 g = ent->colormod[1] * colorscale;
1871                                 b = ent->colormod[2] * colorscale;
1872                                 a = texture->currentalpha;
1873                                 base = r_ambient.value * (1.0f / 64.0f);
1874                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1875                                 {
1876                                         c[0] = base;
1877                                         c[1] = base;
1878                                         c[2] = base;
1879                                         if (surface->dlightframe == r_framecount)
1880                                         {
1881                                                 // TODO: make this work with autosprite which uses identitymatrix
1882                                                 Matrix4x4_Transform(&ent->matrix, v, worldvertex);
1883                                                 for (l = 0;l < r_numdlights;l++)
1884                                                 {
1885                                                         if (surface->dlightbits[l >> 5] & (1 << (l & 31)))
1886                                                         {
1887                                                                 float f2;
1888                                                                 dlight_t *light = &r_dlight[l];
1889                                                                 f2 = VectorDistance2(worldvertex, light->origin) + LIGHTOFFSET;
1890                                                                 if (f2 < light->rtlight.lightmap_cullradius2)
1891                                                                 {
1892                                                                         f2 = (1.0f / f2) - light->rtlight.lightmap_subtract;
1893                                                                         VectorMA(c, f2, light->rtlight.lightmap_light, c);
1894                                                                 }
1895                                                         }
1896                                                 }
1897                                         }
1898                                         c[0] *= r;
1899                                         c[1] *= g;
1900                                         c[2] *= b;
1901                                         if (fogenabled)
1902                                         {
1903                                                 VectorSubtract(v, modelorg, diff);
1904                                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
1905                                                 VectorScale(c, f, c);
1906                                         }
1907                                         if (surface->mesh.data_lightmapcolor4f)
1908                                                 c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1909                                         else
1910                                                 c[3] = a;
1911                                 }
1912                                 R_Mesh_State(&m);
1913                                 GL_LockArrays(0, surface->mesh.num_vertices);
1914                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1915                                 GL_LockArrays(0, 0);
1916                         }
1917                 }
1918                 else
1919                 {
1920                         memset(&m, 0, sizeof(m));
1921                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1922                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1923                         m.tex[0] = R_GetTexture(texture->skin.base);
1924                         m.texmatrix[0] = scrollmatrix;
1925                         m.pointer_color = varray_color4f;
1926                         colorscale = 1;
1927                         if (gl_combine.integer)
1928                         {
1929                                 m.texrgbscale[0] = 4;
1930                                 colorscale *= 0.25f;
1931                         }
1932                         if (doglow)
1933                         {
1934                                 doglow = false;
1935                                 m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
1936                                 m.tex[1] = R_GetTexture(texture->skin.glow);
1937                                 m.texmatrix[1] = scrollmatrix;
1938                         }
1939                         r = ent->colormod[0] * colorscale;
1940                         g = ent->colormod[1] * colorscale;
1941                         b = ent->colormod[2] * colorscale;
1942                         a = texture->currentalpha;
1943                         base = r_ambient.value * (1.0f / 64.0f);
1944                         if ((ent->flags & RENDER_LIGHT) && !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
1945                         {
1946                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1947                                 {
1948                                         c[0] = base;
1949                                         c[1] = base;
1950                                         c[2] = base;
1951                                         if (surface->styles[0] != 255)
1952                                         {
1953                                                 if (surface->mesh.data_lightmapcolor4f)
1954                                                 {
1955                                                         float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 128.0f);
1956                                                         VectorMA(c, scale, surface->mesh.data_lightmapcolor4f + i*4, c);
1957                                                 }
1958                                                 else if (surface->mesh.data_lightmapoffsets)
1959                                                 {
1960                                                         const qbyte *lm = surface->samples + surface->mesh.data_lightmapoffsets[i];
1961                                                         float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 32768.0f);
1962                                                         VectorMA(c, scale, lm, c);
1963                                                         if (surface->styles[1] != 255)
1964                                                         {
1965                                                                 int size3 = ((surface->extents[0]>>4)+1)*((surface->extents[1]>>4)+1)*3;
1966                                                                 lm += size3;
1967                                                                 scale = d_lightstylevalue[surface->styles[1]] * (1.0f / 32768.0f);
1968                                                                 VectorMA(c, scale, lm, c);
1969                                                                 if (surface->styles[2] != 255)
1970                                                                 {
1971                                                                         lm += size3;
1972                                                                         scale = d_lightstylevalue[surface->styles[2]] * (1.0f / 32768.0f);
1973                                                                         VectorMA(c, scale, lm, c);
1974                                                                         if (surface->styles[3] != 255)
1975                                                                         {
1976                                                                                 lm += size3;
1977                                                                                 scale = d_lightstylevalue[surface->styles[3]] * (1.0f / 32768.0f);
1978                                                                                 VectorMA(c, scale, lm, c);
1979                                                                         }
1980                                                                 }
1981                                                         }
1982                                                 }
1983                                         }
1984                                         if (surface->dlightframe == r_framecount)
1985                                         {
1986                                                 // TODO: make this work with autosprite which uses identitymatrix
1987                                                 Matrix4x4_Transform(&ent->matrix, v, worldvertex);
1988                                                 for (l = 0;l < r_numdlights;l++)
1989                                                 {
1990                                                         if (surface->dlightbits[l >> 5] & (1 << (l & 31)))
1991                                                         {
1992                                                                 float f2;
1993                                                                 dlight_t *light = &r_dlight[l];
1994                                                                 f2 = VectorDistance2(worldvertex, light->origin) + LIGHTOFFSET;
1995                                                                 if (f2 < light->rtlight.lightmap_cullradius2)
1996                                                                 {
1997                                                                         f2 = (1.0f / f2) - light->rtlight.lightmap_subtract;
1998                                                                         VectorMA(c, f2, light->rtlight.lightmap_light, c);
1999                                                                 }
2000                                                         }
2001                                                 }
2002                                         }
2003                                         c[0] *= r;
2004                                         c[1] *= g;
2005                                         c[2] *= b;
2006                                         if (fogenabled)
2007                                         {
2008                                                 VectorSubtract(v, modelorg, diff);
2009                                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
2010                                                 VectorScale(c, f, c);
2011                                         }
2012                                         if (surface->mesh.data_lightmapcolor4f)
2013                                                 c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
2014                                         else
2015                                                 c[3] = a;
2016                                 }
2017                         }
2018                         else
2019                         {
2020                                 if (fogenabled)
2021                                 {
2022                                         if (surface->mesh.data_lightmapcolor4f)
2023                                         {
2024                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
2025                                                 {
2026                                                         VectorSubtract(v, modelorg, diff);
2027                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
2028                                                         c[0] = r * f;
2029                                                         c[1] = g * f;
2030                                                         c[2] = b * f;
2031                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
2032                                                 }
2033                                         }
2034                                         else
2035                                         {
2036                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
2037                                                 {
2038                                                         VectorSubtract(v, modelorg, diff);
2039                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
2040                                                         c[0] = r * f;
2041                                                         c[1] = g * f;
2042                                                         c[2] = b * f;
2043                                                         c[3] = a;
2044                                                 }
2045                                         }
2046                                 }
2047                                 else
2048                                 {
2049                                         if (surface->mesh.data_lightmapcolor4f)
2050                                         {
2051                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
2052                                                 {
2053                                                         c[0] = r;
2054                                                         c[1] = g;
2055                                                         c[2] = b;
2056                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
2057                                                 }
2058                                         }
2059                                         else
2060                                         {
2061                                                 m.pointer_color = NULL;
2062                                                 GL_Color(r, g, b, a);
2063                                         }
2064                                 }
2065                         }
2066                         R_Mesh_State(&m);
2067                         GL_LockArrays(0, surface->mesh.num_vertices);
2068                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2069                         GL_LockArrays(0, 0);
2070                 }
2071                 // note: dodetail is never set if transparent
2072                 if (dodetail)
2073                 {
2074                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2075                         GL_DepthMask(false);
2076                         memset(&m, 0, sizeof(m));
2077                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
2078                         m.pointer_texcoord[0] = surface->mesh.data_texcoorddetail2f;
2079                         m.tex[0] = R_GetTexture(texture->skin.detail);
2080                         m.pointer_color = varray_color4f;
2081                         RSurf_FoggedColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, ent->colormod[0], ent->colormod[1], ent->colormod[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg);
2082                         R_Mesh_State(&m);
2083                         GL_LockArrays(0, surface->mesh.num_vertices);
2084                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2085                         GL_LockArrays(0, 0);
2086                 }
2087                 if (doglow)
2088                 {
2089                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2090                         GL_DepthMask(false);
2091                         memset(&m, 0, sizeof(m));
2092                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
2093                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2094                         m.tex[0] = R_GetTexture(texture->skin.glow);
2095                         m.texmatrix[0] = scrollmatrix;
2096                         m.pointer_color = varray_color4f;
2097                         RSurf_FoggedColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, ent->colormod[0], ent->colormod[1], ent->colormod[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg);
2098                         R_Mesh_State(&m);
2099                         GL_LockArrays(0, surface->mesh.num_vertices);
2100                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2101                         GL_LockArrays(0, 0);
2102                 }
2103                 if (fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_ADD))
2104                 {
2105                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2106                         GL_DepthMask(false);
2107                         memset(&m, 0, sizeof(m));
2108                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
2109                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2110                         m.tex[0] = R_GetTexture(texture->skin.fog);
2111                         m.texmatrix[0] = scrollmatrix;
2112                         m.pointer_color = varray_color4f;
2113                         RSurf_FogPassColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg);
2114                         R_Mesh_State(&m);
2115                         GL_LockArrays(0, surface->mesh.num_vertices);
2116                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2117                         GL_LockArrays(0, 0);
2118                 }
2119         }
2120         if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2121                 qglEnable(GL_CULL_FACE);
2122 #endif
2123 }
2124
2125 #ifdef LHREMOVESOON
2126 void R_DrawSurfaceList(entity_render_t *ent, texture_t *texture, int texturenumsurfaces, msurface_t **texturesurfacelist)
2127 {
2128         int texturesurfaceindex;
2129         vec3_t tempcenter, center, modelorg;
2130         msurface_t *surface;
2131         qboolean dolightmap;
2132         qboolean dobase;
2133         qboolean doambient;
2134         qboolean dodetail;
2135         qboolean doglow;
2136         qboolean dofog;
2137         rmeshstate_t m;
2138         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
2139         c_faces += texturenumsurfaces;
2140         // gl_lightmaps debugging mode skips normal texturing
2141         if (gl_lightmaps.integer)
2142         {
2143                 GL_BlendFunc(GL_ONE, GL_ZERO);
2144                 GL_DepthMask(true);
2145                 GL_DepthTest(true);
2146                 qglDisable(GL_CULL_FACE);
2147                 GL_Color(1, 1, 1, 1);
2148                 memset(&m, 0, sizeof(m));
2149                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2150                 {
2151                         surface = texturesurfacelist[texturesurfaceindex];
2152                         m.tex[0] = R_GetTexture(surface->lightmaptexture);
2153                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
2154                         if (surface->lightmaptexture)
2155                         {
2156                                 GL_Color(1, 1, 1, 1);
2157                                 m.pointer_color = NULL;
2158                         }
2159                         else
2160                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
2161                         m.pointer_vertex = surface->mesh.data_vertex3f;
2162                         R_Mesh_State(&m);
2163                         GL_LockArrays(0, surface->mesh.num_vertices);
2164                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2165                         GL_LockArrays(0, 0);
2166                 }
2167                 qglEnable(GL_CULL_FACE);
2168                 return;
2169         }
2170         if (texture->currentmaterialflags & MATERIALFLAG_WALL)
2171         {
2172                 dolightmap = (ent->flags & RENDER_LIGHT);
2173                 dobase = true;
2174                 doambient = r_ambient.value > 0;
2175                 dodetail = texture->skin.detail != NULL && r_detailtextures.integer != 0;
2176                 doglow = texture->skin.glow != NULL;
2177                 dofog = fogenabled;
2178                 // multitexture cases
2179                 if (r_textureunits.integer >= 2 && gl_combine.integer && dobase && dolightmap)
2180                 {
2181                         GL_BlendFunc(GL_ONE, GL_ZERO);
2182                         GL_DepthMask(true);
2183                         GL_DepthTest(true);
2184                         GL_Color(1, 1, 1, 1);
2185                         GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
2186                         memset(&m, 0, sizeof(m));
2187                         m.tex[0] = R_GetTexture(texture->skin.base);
2188                         dobase = false;
2189                         m.texrgbscale[1] = 2;
2190                         dolightmap = false;
2191                         if (r_textureunits.integer >= 4 && !doambient && dodetail && doglow)
2192                         {
2193                                 m.tex[2] = R_GetTexture(texture->skin.detail);
2194                                 m.texrgbscale[2] = 2;
2195                                 dodetail = false;
2196                                 m.tex[3] = R_GetTexture(texture->skin.glow);
2197                                 m.texcombinergb[3] = GL_ADD;
2198                                 doglow = false;
2199                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2200                                 {
2201                                         surface = texturesurfacelist[texturesurfaceindex];
2202                                         m.tex[1] = R_GetTexture(surface->lightmaptexture);
2203                                         m.pointer_vertex = surface->mesh.data_vertex3f;
2204                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2205                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
2206                                         m.pointer_texcoord[2] = surface->mesh.data_texcoorddetail2f;
2207                                         m.pointer_texcoord[3] = surface->mesh.data_texcoordtexture2f;
2208                                         R_Mesh_State(&m);
2209                                         GL_LockArrays(0, surface->mesh.num_vertices);
2210                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2211                                         GL_LockArrays(0, 0);
2212                                 }
2213                         }
2214                         else if (r_textureunits.integer >= 3 && !doambient && dodetail)
2215                         {
2216                                 m.tex[2] = R_GetTexture(texture->skin.detail);
2217                                 m.texrgbscale[2] = 2;
2218                                 dodetail = false;
2219                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2220                                 {
2221                                         surface = texturesurfacelist[texturesurfaceindex];
2222                                         m.tex[1] = R_GetTexture(surface->lightmaptexture);
2223                                         m.pointer_vertex = surface->mesh.data_vertex3f;
2224                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2225                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
2226                                         m.pointer_texcoord[2] = surface->mesh.data_texcoorddetail2f;
2227                                         R_Mesh_State(&m);
2228                                         GL_LockArrays(0, surface->mesh.num_vertices);
2229                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2230                                         GL_LockArrays(0, 0);
2231                                 }
2232                         }
2233                         else if (r_textureunits.integer >= 3 && !doambient && !dodetail && doglow)
2234                         {
2235                                 m.tex[2] = R_GetTexture(texture->skin.glow);
2236                                 m.texcombinergb[2] = GL_ADD;
2237                                 doglow = false;
2238                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2239                                 {
2240                                         surface = texturesurfacelist[texturesurfaceindex];
2241                                         m.tex[1] = R_GetTexture(surface->lightmaptexture);
2242                                         m.pointer_vertex = surface->mesh.data_vertex3f;
2243                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2244                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
2245                                         m.pointer_texcoord[2] = surface->mesh.data_texcoordtexture2f;
2246                                         R_Mesh_State(&m);
2247                                         GL_LockArrays(0, surface->mesh.num_vertices);
2248                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2249                                         GL_LockArrays(0, 0);
2250                                 }
2251                         }
2252                         else
2253                         {
2254                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2255                                 {
2256                                         surface = texturesurfacelist[texturesurfaceindex];
2257                                         m.tex[1] = R_GetTexture(surface->lightmaptexture);
2258                                         m.pointer_vertex = surface->mesh.data_vertex3f;
2259                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2260                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
2261                                         R_Mesh_State(&m);
2262                                         GL_LockArrays(0, surface->mesh.num_vertices);
2263                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2264                                         GL_LockArrays(0, 0);
2265                                 }
2266                         }
2267                 }
2268                 // anything not handled above
2269                 if (dobase)
2270                 {
2271                         GL_BlendFunc(GL_ONE, GL_ZERO);
2272                         GL_DepthMask(true);
2273                         GL_DepthTest(true);
2274                         GL_Color(1, 1, 1, 1);
2275                         if (ent->flags & RENDER_LIGHT)
2276                                 GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
2277                         else
2278                                 GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], 1);
2279                         memset(&m, 0, sizeof(m));
2280                         m.tex[0] = R_GetTexture(texture->skin.base);
2281                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2282                         {
2283                                 surface = texturesurfacelist[texturesurfaceindex];
2284                                 m.pointer_vertex = surface->mesh.data_vertex3f;
2285                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2286                                 R_Mesh_State(&m);
2287                                 GL_LockArrays(0, surface->mesh.num_vertices);
2288                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2289                                 GL_LockArrays(0, 0);
2290                         }
2291                 }
2292                 GL_DepthMask(false);
2293                 if (dolightmap)
2294                 {
2295                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2296                         GL_DepthMask(false);
2297                         GL_DepthTest(true);
2298                         GL_Color(1, 1, 1, 1);
2299                         memset(&m, 0, sizeof(m));
2300                         m.tex[0] = R_GetTexture(texture->skin.base);
2301                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2302                         {
2303                                 surface = texturesurfacelist[texturesurfaceindex];
2304                                 m.tex[0] = R_GetTexture(surface->lightmaptexture);
2305                                 m.pointer_vertex = surface->mesh.data_vertex3f;
2306                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
2307                                 R_Mesh_State(&m);
2308                                 GL_LockArrays(0, surface->mesh.num_vertices);
2309                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2310                                 GL_LockArrays(0, 0);
2311                         }
2312                 }
2313                 if (doambient)
2314                 {
2315                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2316                         GL_DepthMask(false);
2317                         GL_DepthTest(true);
2318                         memset(&m, 0, sizeof(m));
2319                         GL_Color(r_ambient.value * (1.0f / 128.0f) * ent->colormod[0], r_ambient.value * (1.0f / 128.0f) * ent->colormod[1], r_ambient.value * (1.0f / 128.0f) * ent->colormod[2], 1);
2320                         m.tex[0] = R_GetTexture(texture->skin.base);
2321                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2322                         {
2323                                 surface = texturesurfacelist[texturesurfaceindex];
2324                                 m.pointer_vertex = surface->mesh.data_vertex3f;
2325                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2326                                 R_Mesh_State(&m);
2327                                 GL_LockArrays(0, surface->mesh.num_vertices);
2328                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2329                                 GL_LockArrays(0, 0);
2330                         }
2331                 }
2332                 if (dodetail)
2333                 {
2334                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2335                         GL_DepthMask(false);
2336                         GL_DepthTest(true);
2337                         GL_Color(1, 1, 1, 1);
2338                         memset(&m, 0, sizeof(m));
2339                         m.tex[0] = R_GetTexture(texture->skin.detail);
2340                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2341                         {
2342                                 surface = texturesurfacelist[texturesurfaceindex];
2343                                 m.pointer_vertex = surface->mesh.data_vertex3f;
2344                                 m.pointer_texcoord[0] = surface->mesh.data_texcoorddetail2f;
2345                                 R_Mesh_State(&m);
2346                                 GL_LockArrays(0, surface->mesh.num_vertices);
2347                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2348                                 GL_LockArrays(0, 0);
2349                         }
2350                 }
2351                 if (doglow)
2352                 {
2353                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2354                         GL_DepthMask(false);
2355                         GL_DepthTest(true);
2356                         GL_Color(1, 1, 1, 1);
2357                         memset(&m, 0, sizeof(m));
2358                         m.tex[0] = R_GetTexture(texture->skin.glow);
2359                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2360                         {
2361                                 surface = texturesurfacelist[texturesurfaceindex];
2362                                 m.pointer_vertex = surface->mesh.data_vertex3f;
2363                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2364                                 R_Mesh_State(&m);
2365                                 GL_LockArrays(0, surface->mesh.num_vertices);
2366                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2367                                 GL_LockArrays(0, 0);
2368                         }
2369                 }
2370                 if (dofog)
2371                 {
2372                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2373                         GL_DepthMask(false);
2374                         GL_DepthTest(true);
2375                         memset(&m, 0, sizeof(m));
2376                         m.pointer_color = varray_color4f;
2377                         m.tex[0] = R_GetTexture(texture->skin.glow);
2378                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2379                         {
2380                                 surface = texturesurfacelist[texturesurfaceindex];
2381                                 m.pointer_vertex = surface->mesh.data_vertex3f;
2382                                 if (m.tex[0])
2383                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2384                                 R_Mesh_State(&m);
2385                                 RSurf_FogPassColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], 1, 1, surface->mesh.num_vertices, modelorg);
2386                                 GL_LockArrays(0, surface->mesh.num_vertices);
2387                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2388                                 GL_LockArrays(0, 0);
2389                         }
2390                 }
2391                 return;
2392         }
2393         if (texture->currentmaterialflags & MATERIALFLAG_WATER)
2394         {
2395                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2396                 {
2397                         surface = texturesurfacelist[texturesurfaceindex];
2398                         RSurfShader_Transparent_Callback(ent, surface - ent->model->brush.data_surfaces);
2399                 }
2400                 return;
2401         }
2402         if (texture->currentmaterialflags & MATERIALFLAG_SKY)
2403         {
2404                 if (skyrendernow)
2405                 {
2406                         skyrendernow = false;
2407                         if (skyrendermasked)
2408                                 R_Sky();
2409                 }
2410                 // LordHavoc: HalfLife maps have freaky skypolys...
2411                 if (!ent->model->brush.ishlbsp)
2412                 {
2413                         R_Mesh_Matrix(&ent->matrix);
2414                         GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1);
2415                         if (skyrendermasked)
2416                         {
2417                                 // depth-only (masking)
2418                                 GL_ColorMask(0,0,0,0);
2419                                 // just to make sure that braindead drivers don't draw anything
2420                                 // despite that colormask...
2421                                 GL_BlendFunc(GL_ZERO, GL_ONE);
2422                         }
2423                         else
2424                         {
2425                                 // fog sky
2426                                 GL_BlendFunc(GL_ONE, GL_ZERO);
2427                         }
2428                         GL_DepthMask(true);
2429                         GL_DepthTest(true);
2430                         memset(&m, 0, sizeof(m));
2431                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2432                         {
2433                                 surface = texturesurfacelist[texturesurfaceindex];
2434                                 m.pointer_vertex = surface->mesh.data_vertex3f;
2435                                 R_Mesh_State(&m);
2436                                 GL_LockArrays(0, surface->mesh.num_vertices);
2437                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2438                                 GL_LockArrays(0, 0);
2439                         }
2440                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
2441                 }
2442                 return;
2443         }
2444 }
2445 #endif
2446
2447 void R_QueueSurfaceList(entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
2448 {
2449         int texturesurfaceindex;
2450         const msurface_t *surface;
2451         vec3_t tempcenter, center;
2452         if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
2453         {
2454                 // drawing sky transparently would be too difficult
2455                 if (!(texture->currentmaterialflags & MATERIALFLAG_SKY))
2456                 {
2457                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2458                         {
2459                                 surface = texturesurfacelist[texturesurfaceindex];
2460                                 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
2461                                 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
2462                                 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
2463                                 Matrix4x4_Transform(&ent->matrix, tempcenter, center);
2464                                 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->brush.data_surfaces);
2465                         }
2466                 }
2467         }
2468         else
2469                 R_DrawSurfaceList(ent, texture, texturenumsurfaces, texturesurfacelist, modelorg);
2470 }
2471
2472 void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
2473 {
2474         int i, j, f, flagsmask;
2475         msurface_t *surface, **surfacechain;
2476         texture_t *t, *texture;
2477         model_t *model = ent->model;
2478         vec3_t modelorg;
2479         const int maxsurfacelist = 1024;
2480         int numsurfacelist = 0;
2481         const msurface_t *surfacelist[1024];
2482         if (model == NULL)
2483                 return;
2484         R_Mesh_Matrix(&ent->matrix);
2485         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
2486
2487 #ifdef LHREMOVESOON
2488         if (ent != r_refdef.worldentity)
2489         {
2490                 // because bmodels can be reused, we have to clear dlightframe every time
2491                 surface = model->brush.data_surfaces + model->firstmodelsurface;
2492                 for (i = 0;i < model->nummodelsurfaces;i++, surface++)
2493                         surface->dlightframe = -1;
2494         }
2495 #endif
2496
2497         // update light styles
2498         if (!skysurfaces)
2499         {
2500 #ifdef LHREMOVESOON
2501                 if (r_dynamic.integer && !r_rtdlight)
2502                         R_MarkLights(ent);
2503 #endif
2504                 for (i = 0;i < model->brushq1.light_styles;i++)
2505                 {
2506                         if (model->brushq1.light_stylevalue[i] != d_lightstylevalue[model->brushq1.light_style[i]])
2507                         {
2508                                 model->brushq1.light_stylevalue[i] = d_lightstylevalue[model->brushq1.light_style[i]];
2509                                 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
2510                                         for (;(surface = *surfacechain);surfacechain++)
2511                                                 surface->cached_dlight = true;
2512                         }
2513                 }
2514         }
2515
2516         R_UpdateAllTextureInfo(ent);
2517         flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
2518         f = 0;
2519         t = NULL;
2520         texture = NULL;
2521         numsurfacelist = 0;
2522         for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2523         {
2524                 if (ent != r_refdef.worldentity || r_worldsurfacevisible[j])
2525                 {
2526                         surface = model->brush.data_surfaces + j;
2527                         if (t != surface->texture)
2528                         {
2529                                 if (numsurfacelist)
2530                                 {
2531                                         R_QueueSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2532                                         numsurfacelist = 0;
2533                                 }
2534                                 t = surface->texture;
2535                                 f = t->currentmaterialflags & flagsmask;
2536                                 texture = t->currentframe;
2537                         }
2538                         if (f)
2539                         {
2540                                 // if lightmap parameters changed, rebuild lightmap texture
2541                                 if (surface->cached_dlight && surface->samples)
2542                                         R_BuildLightMap(ent, surface);
2543                                 // add face to draw list
2544                                 surfacelist[numsurfacelist++] = surface;
2545                                 if (numsurfacelist >= maxsurfacelist)
2546                                 {
2547                                         R_QueueSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2548                                         numsurfacelist = 0;
2549                                 }
2550                         }
2551                 }
2552         }
2553         if (numsurfacelist)
2554                 R_QueueSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2555 }
2556
2557 static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
2558 {
2559         int i;
2560         float *v;
2561         rmeshstate_t m;
2562         const mportal_t *portal = calldata1;
2563         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2564         GL_DepthMask(false);
2565         GL_DepthTest(true);
2566         R_Mesh_Matrix(&r_identitymatrix);
2567
2568         memset(&m, 0, sizeof(m));
2569         m.pointer_vertex = varray_vertex3f;
2570         R_Mesh_State(&m);
2571
2572         i = calldata2;
2573         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f),
2574                          ((i & 0x0038) >> 3) * (1.0f / 7.0f),
2575                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f),
2576                          0.125f);
2577         if (PlaneDiff(r_vieworigin, (&portal->plane)) < 0)
2578         {
2579                 for (i = portal->numpoints - 1, v = varray_vertex3f;i >= 0;i--, v += 3)
2580                         VectorCopy(portal->points[i].position, v);
2581         }
2582         else
2583                 for (i = 0, v = varray_vertex3f;i < portal->numpoints;i++, v += 3)
2584                         VectorCopy(portal->points[i].position, v);
2585         GL_LockArrays(0, portal->numpoints);
2586         R_Mesh_Draw(portal->numpoints, portal->numpoints - 2, polygonelements);
2587         GL_LockArrays(0, 0);
2588 }
2589
2590 // LordHavoc: this is just a nice debugging tool, very slow
2591 static void R_DrawPortals(void)
2592 {
2593         int i, portalnum;
2594         mportal_t *portal;
2595         float center[3], f;
2596         model_t *model = r_refdef.worldmodel;
2597         if (model == NULL)
2598                 return;
2599         for (portalnum = 0, portal = model->brush.data_portals;portalnum < model->brush.num_portals;portalnum++, portal++)
2600         {
2601                 if (portal->numpoints <= POLYGONELEMENTS_MAXPOINTS)
2602                 if (!R_CullBox(portal->mins, portal->maxs))
2603                 {
2604                         VectorClear(center);
2605                         for (i = 0;i < portal->numpoints;i++)
2606                                 VectorAdd(center, portal->points[i].position, center);
2607                         f = ixtable[portal->numpoints];
2608                         VectorScale(center, f, center);
2609                         R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, portal, portalnum);
2610                 }
2611         }
2612 }
2613
2614 static void R_DrawCollisionBrush(colbrushf_t *brush)
2615 {
2616         int i;
2617         rmeshstate_t m;
2618         memset(&m, 0, sizeof(m));
2619         m.pointer_vertex = brush->points->v;
2620         R_Mesh_State(&m);
2621         i = (int)(((size_t)brush) / sizeof(colbrushf_t));
2622         GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
2623         GL_LockArrays(0, brush->numpoints);
2624         R_Mesh_Draw(brush->numpoints, brush->numtriangles, brush->elements);
2625         GL_LockArrays(0, 0);
2626 }
2627
2628 static void R_DrawCollisionSurface(entity_render_t *ent, msurface_t *surface)
2629 {
2630         int i;
2631         rmeshstate_t m;
2632         if (!surface->mesh.num_collisiontriangles)
2633                 return;
2634         memset(&m, 0, sizeof(m));
2635         m.pointer_vertex = surface->mesh.data_collisionvertex3f;
2636         R_Mesh_State(&m);
2637         i = (int)(((size_t)surface) / sizeof(msurface_t));
2638         GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
2639         GL_LockArrays(0, surface->mesh.num_collisionvertices);
2640         R_Mesh_Draw(surface->mesh.num_collisionvertices, surface->mesh.num_collisiontriangles, surface->mesh.data_collisionelement3i);
2641         GL_LockArrays(0, 0);
2642 }
2643
2644 void R_WorldVisibility(void)
2645 {
2646         int i, j, *mark;
2647         mleaf_t *leaf;
2648         mleaf_t *viewleaf;
2649         model_t *model = r_refdef.worldmodel;
2650
2651         if (!model)
2652                 return;
2653
2654         // if possible find the leaf the view origin is in
2655         viewleaf = model->brushq1.PointInLeaf ? model->brushq1.PointInLeaf(model, r_vieworigin) : NULL;
2656         // if possible fetch the visible cluster bits
2657         if (model->brush.FatPVS)
2658                 model->brush.FatPVS(model, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
2659
2660         // clear the visible surface and leaf flags arrays
2661         memset(r_worldsurfacevisible, 0, model->brush.num_surfaces);
2662         memset(r_worldleafvisible, 0, model->brush.num_leafs);
2663
2664         // if the user prefers surfaceworldnode (testing?) or the viewleaf could
2665         // not be found, or the viewleaf is not part of the visible world
2666         // (floating around in the void), use the pvs method
2667         if (r_surfaceworldnode.integer || !viewleaf || viewleaf->clusterindex < 0)
2668         {
2669                 // pvs method:
2670                 // similar to quake's RecursiveWorldNode but without cache misses
2671                 for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
2672                 {
2673                         // if leaf is in current pvs and on the screen, mark its surfaces
2674                         if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs))
2675                         {
2676                                 c_leafs++;
2677                                 r_worldleafvisible[j] = true;
2678                                 if (leaf->numleafsurfaces)
2679                                         for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
2680                                                 r_worldsurfacevisible[*mark] = true;
2681                         }
2682                 }
2683         }
2684         else
2685         {
2686                 int leafstackpos;
2687                 mportal_t *p;
2688                 mleaf_t *leafstack[8192];
2689                 // portal method:
2690                 // follows portals leading outward from viewleaf, does not venture
2691                 // offscreen or into leafs that are not visible, faster than Quake's
2692                 // RecursiveWorldNode and vastly better in unvised maps, often culls a
2693                 // lot of surface that pvs alone would miss
2694                 leafstack[0] = viewleaf;
2695                 leafstackpos = 1;
2696                 while (leafstackpos)
2697                 {
2698                         c_leafs++;
2699                         leaf = leafstack[--leafstackpos];
2700                         r_worldleafvisible[leaf - model->brush.data_leafs] = true;
2701                         // mark any surfaces bounding this leaf
2702                         if (leaf->numleafsurfaces)
2703                                 for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
2704                                         r_worldsurfacevisible[*mark] = true;
2705                         // follow portals into other leafs
2706                         // the checks are:
2707                         // if viewer is behind portal (portal faces outward into the scene)
2708                         // and the portal polygon's bounding box is on the screen
2709                         // and the leaf has not been visited yet
2710                         // and the leaf is visible in the pvs
2711                         // (the first two checks won't cause as many cache misses as the leaf checks)
2712                         for (p = leaf->portals;p;p = p->next)
2713                                 if (DotProduct(r_vieworigin, p->plane.normal) < (p->plane.dist + 1) && !R_CullBox(p->mins, p->maxs) && !r_worldleafvisible[p->past - model->brush.data_leafs] && CHECKPVSBIT(r_pvsbits, p->past->clusterindex))
2714                                         leafstack[leafstackpos++] = p->past;
2715                 }
2716         }
2717
2718         if (r_drawportals.integer)
2719                 R_DrawPortals();
2720 }
2721
2722 void R_Q1BSP_DrawSky(entity_render_t *ent)
2723 {
2724         if (ent->model == NULL)
2725                 return;
2726         if (r_drawcollisionbrushes.integer < 2)
2727                 R_DrawSurfaces(ent, true);
2728 }
2729
2730 void R_Q1BSP_Draw(entity_render_t *ent)
2731 {
2732         if (ent->model == NULL)
2733                 return;
2734         c_bmodels++;
2735         if (r_drawcollisionbrushes.integer < 2)
2736                 R_DrawSurfaces(ent, false);
2737         if (r_drawcollisionbrushes.integer >= 1 && ent->model->brush.num_brushes)
2738         {
2739                 int i;
2740                 model_t *model = ent->model;
2741                 msurface_t *surface;
2742                 q3mbrush_t *brush;
2743                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2744                 GL_DepthMask(false);
2745                 GL_DepthTest(true);
2746                 qglPolygonOffset(r_drawcollisionbrushes_polygonfactor.value, r_drawcollisionbrushes_polygonoffset.value);
2747                 for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
2748                         if (brush->colbrushf && brush->colbrushf->numtriangles)
2749                                 R_DrawCollisionBrush(brush->colbrushf);
2750                 for (i = 0, surface = model->brush.data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
2751                         if (surface->mesh.num_collisiontriangles)
2752                                 R_DrawCollisionSurface(ent, surface);
2753                 qglPolygonOffset(0, 0);
2754         }
2755 }
2756
2757 void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer)
2758 {
2759         model_t *model = ent->model;
2760         vec3_t lightmins, lightmaxs;
2761         int t, leafindex, leafsurfaceindex, surfaceindex, triangleindex, outnumclusters = 0, outnumsurfaces = 0;
2762         const int *e;
2763         const float *v[3];
2764         msurface_t *surface;
2765         mleaf_t *leaf;
2766         const qbyte *pvs;
2767         lightmins[0] = relativelightorigin[0] - lightradius;
2768         lightmins[1] = relativelightorigin[1] - lightradius;
2769         lightmins[2] = relativelightorigin[2] - lightradius;
2770         lightmaxs[0] = relativelightorigin[0] + lightradius;
2771         lightmaxs[1] = relativelightorigin[1] + lightradius;
2772         lightmaxs[2] = relativelightorigin[2] + lightradius;
2773         *outnumclusterspointer = 0;
2774         *outnumsurfacespointer = 0;
2775         memset(outclusterpvs, 0, model->brush.num_pvsclusterbytes);
2776         memset(outsurfacepvs, 0, (model->nummodelsurfaces + 7) >> 3);
2777         if (model == NULL)
2778         {
2779                 VectorCopy(lightmins, outmins);
2780                 VectorCopy(lightmaxs, outmaxs);
2781                 return;
2782         }
2783         VectorCopy(relativelightorigin, outmins);
2784         VectorCopy(relativelightorigin, outmaxs);
2785         if (model->brush.GetPVS)
2786                 pvs = model->brush.GetPVS(model, relativelightorigin);
2787         else
2788                 pvs = NULL;
2789         R_UpdateAllTextureInfo(ent);
2790         // FIXME: use BSP recursion as lights are often small
2791         for (leafindex = 0, leaf = model->brush.data_leafs;leafindex < model->brush.num_leafs;leafindex++, leaf++)
2792         {
2793                 if (BoxesOverlap(lightmins, lightmaxs, leaf->mins, leaf->maxs) && (pvs == NULL || CHECKPVSBIT(pvs, leaf->clusterindex)))
2794                 {
2795                         outmins[0] = min(outmins[0], leaf->mins[0]);
2796                         outmins[1] = min(outmins[1], leaf->mins[1]);
2797                         outmins[2] = min(outmins[2], leaf->mins[2]);
2798                         outmaxs[0] = max(outmaxs[0], leaf->maxs[0]);
2799                         outmaxs[1] = max(outmaxs[1], leaf->maxs[1]);
2800                         outmaxs[2] = max(outmaxs[2], leaf->maxs[2]);
2801                         if (outclusterpvs)
2802                         {
2803                                 if (!CHECKPVSBIT(outclusterpvs, leaf->clusterindex))
2804                                 {
2805                                         SETPVSBIT(outclusterpvs, leaf->clusterindex);
2806                                         outclusterlist[outnumclusters++] = leaf->clusterindex;
2807                                 }
2808                         }
2809                         if (outsurfacepvs)
2810                         {
2811                                 for (leafsurfaceindex = 0;leafsurfaceindex < leaf->numleafsurfaces;leafsurfaceindex++)
2812                                 {
2813                                         surfaceindex = leaf->firstleafsurface[leafsurfaceindex];
2814                                         if (!CHECKPVSBIT(outsurfacepvs, surfaceindex))
2815                                         {
2816                                                 surface = model->brush.data_surfaces + surfaceindex;
2817                                                 if (BoxesOverlap(lightmins, lightmaxs, surface->mins, surface->maxs))
2818                                                 if ((surface->texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL)
2819                                                 {
2820                                                         for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->mesh.num_triangles;triangleindex++, t++, e += 3)
2821                                                         {