+ int lnum, s, t, smax, tmax, smax3, lit, impacts, impactt;
+ float sdtable[256], *bl, k, dist, dist2, maxdist, maxdist2, maxdist3, td1, td, red, green, blue, impact[3], local[3], subtract;
+
+ lit = false;
+
+ smax = (surf->extents[0] >> 4) + 1;
+ tmax = (surf->extents[1] >> 4) + 1;
+ smax3 = smax * 3;
+
+ for (lnum = 0; lnum < r_numdlights; lnum++)
+ {
+ if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
+ continue; // not lit by this light
+
+ Matrix4x4_Transform(matrix, r_dlight[lnum].origin, local);
+ dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
+
+ // for comparisons to minimum acceptable light
+ // compensate for LIGHTOFFSET
+ maxdist = (int) r_dlight[lnum].cullradius2 + LIGHTOFFSET;
+
+ dist2 = dist * dist;
+ dist2 += LIGHTOFFSET;
+ if (dist2 >= maxdist)
+ continue;
+
+ if (surf->plane->type < 3)
+ {
+ VectorCopy(local, impact);
+ impact[surf->plane->type] -= dist;
+ }
+ else
+ {
+ impact[0] = local[0] - surf->plane->normal[0] * dist;
+ impact[1] = local[1] - surf->plane->normal[1] * dist;
+ impact[2] = local[2] - surf->plane->normal[2] * dist;
+ }
+
+ impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
+ impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
+
+ td = bound(0, impacts, smax * 16) - impacts;
+ td1 = bound(0, impactt, tmax * 16) - impactt;
+ td = td * td + td1 * td1 + dist2;
+ if (td > maxdist)
+ continue;
+
+ // reduce calculations
+ for (s = 0, td1 = impacts; s < smax; s++, td1 -= 16.0f)
+ sdtable[s] = td1 * td1 + dist2;
+
+ maxdist3 = maxdist - dist2;
+
+ // convert to 8.8 blocklights format
+ red = r_dlight[lnum].light[0];
+ green = r_dlight[lnum].light[1];
+ blue = r_dlight[lnum].light[2];
+ subtract = r_dlight[lnum].subtract * 32768.0f;
+ bl = floatblocklights;
+
+ td1 = impactt;
+ for (t = 0;t < tmax;t++, td1 -= 16.0f)
+ {
+ td = td1 * td1;
+ // make sure some part of it is visible on this line
+ if (td < maxdist3)
+ {
+ maxdist2 = maxdist - td;
+ for (s = 0;s < smax;s++)
+ {
+ if (sdtable[s] < maxdist2)
+ {
+ k = (32768.0f / (sdtable[s] + td)) - subtract;
+ bl[0] += red * k;
+ bl[1] += green * k;
+ bl[2] += blue * k;
+ lit = true;
+ }
+ bl += 3;
+ }
+ }
+ else // skip line
+ bl += smax3;
+ }
+ }
+ return lit;
+}
+
+/*
+===============
+R_BuildLightMap
+
+Combine and scale multiple lightmaps into the 8.8 format in blocklights
+===============
+*/
+static void R_BuildLightMap (const entity_render_t *ent, msurface_t *surf)
+{
+ if (!r_floatbuildlightmap.integer)
+ {
+ int smax, tmax, i, j, size, size3, shift, maps, stride, l;
+ unsigned int *bl, scale;
+ qbyte *lightmap, *out, *stain;
+
+ // update cached lighting info
+ surf->cached_dlight = 0;
+
+ smax = (surf->extents[0]>>4)+1;
+ tmax = (surf->extents[1]>>4)+1;
+ size = smax*tmax;
+ size3 = size*3;
+ lightmap = surf->samples;
+
+ // set to full bright if no light data
+ bl = intblocklights;
+ if ((ent->effects & EF_FULLBRIGHT) || !ent->model->lightdata)
+ {
+ for (i = 0;i < size3;i++)
+ bl[i] = 255*256;
+ }
+ else
+ {
+ // clear to no light
+ j = r_ambient.value * 512.0f; // would be 128.0f logically, but using 512.0f to match winquake style
+ if (j)
+ {
+ for (i = 0;i < size3;i++)
+ *bl++ = j;
+ }
+ else
+ memset(bl, 0, size*3*sizeof(unsigned int));
+
+ if (surf->dlightframe == r_framecount && r_dlightmap.integer)
+ {
+ surf->cached_dlight = R_IntAddDynamicLights(&ent->inversematrix, surf);
+ if (surf->cached_dlight)
+ c_light_polys++;
+ }
+
+ // add all the lightmaps
+ if (lightmap)
+ {
+ bl = intblocklights;
+ for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++, lightmap += size3)
+ for (scale = d_lightstylevalue[surf->styles[maps]], i = 0;i < size3;i++)
+ bl[i] += lightmap[i] * scale;
+ }
+ }
+
+ stain = surf->stainsamples;
+ bl = intblocklights;
+ out = templight;
+ // deal with lightmap brightness scale
+ shift = 7 + r_lightmapscalebit + 8;
+ if (ent->model->lightmaprgba)
+ {
+ stride = (surf->lightmaptexturestride - smax) * 4;
+ for (i = 0;i < tmax;i++, out += stride)
+ {
+ for (j = 0;j < smax;j++)
+ {
+ l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
+ l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
+ l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
+ *out++ = 255;
+ }
+ }
+ }
+ else
+ {
+ stride = (surf->lightmaptexturestride - smax) * 3;
+ for (i = 0;i < tmax;i++, out += stride)
+ {
+ for (j = 0;j < smax;j++)
+ {
+ l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
+ l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
+ l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
+ }
+ }
+ }
+
+ R_UpdateTexture(surf->lightmaptexture, templight);
+ }
+ else
+ {
+ int smax, tmax, i, j, size, size3, maps, stride, l;
+ float *bl, scale;
+ qbyte *lightmap, *out, *stain;
+
+ // update cached lighting info
+ surf->cached_dlight = 0;
+
+ smax = (surf->extents[0]>>4)+1;
+ tmax = (surf->extents[1]>>4)+1;
+ size = smax*tmax;
+ size3 = size*3;
+ lightmap = surf->samples;
+
+ // set to full bright if no light data
+ bl = floatblocklights;
+ if ((ent->effects & EF_FULLBRIGHT) || !ent->model->lightdata)
+ j = 255*256;
+ else
+ j = r_ambient.value * 512.0f; // would be 128.0f logically, but using 512.0f to match winquake style
+
+ // clear to no light
+ if (j)
+ {
+ for (i = 0;i < size3;i++)
+ *bl++ = j;
+ }
+ else
+ memset(bl, 0, size*3*sizeof(float));
+
+ if (surf->dlightframe == r_framecount && r_dlightmap.integer)
+ {
+ surf->cached_dlight = R_FloatAddDynamicLights(&ent->inversematrix, surf);
+ if (surf->cached_dlight)
+ c_light_polys++;
+ }
+
+ // add all the lightmaps
+ if (lightmap)
+ {
+ bl = floatblocklights;
+ for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++, lightmap += size3)
+ for (scale = d_lightstylevalue[surf->styles[maps]], i = 0;i < size3;i++)
+ bl[i] += lightmap[i] * scale;
+ }