diff --git a/include/light/entities.h b/include/light/entities.h index 0277e9b3..7009d609 100644 --- a/include/light/entities.h +++ b/include/light/entities.h @@ -40,6 +40,11 @@ typedef enum { LF_INVERSE = 1, /* Inverse (1/x), scaled by 1/128 */ LF_INVERSE2 = 2, /* Inverse square (1/(x^2)), scaled by 1/(128^2) */ LF_INFINITE = 3, /* No attenuation, same brightness at any distance */ + LF_LOCALMIN = 4, /* No attenuation, non-additive minlight effect within + line of sight of the light source. */ + LF_INVERSE2A = 5, /* Inverse square, with distance adjusted to avoid + exponentially bright values near the source. + (1/(x+128)^2), scaled by 1/(128^2) */ LF_COUNT } light_formula_t; diff --git a/light.txt b/light.txt index 22a0942c..fa8da67f 100644 --- a/light.txt +++ b/light.txt @@ -99,10 +99,15 @@ ENTITY PARAMETERS "delay" "n" Select an attenuation formaula for the light: - 0 => linear attenuation (default) + 0 => Linear attenuation (default) 1 => 1/x attenuation 2 => 1/(x^2) attenuation - 3 => no attenuation (light stays same brightness at any distance) + 3 => No attenuation (light stays same brightness at any distance) + 4 => "local minlight" - No attenuation and like minlight, it won't + raise the lighting above it's light value. Unlike minlight, it + will only affect surfaces within line of sight of the entity. + 5 => 1/(x^2) attenuation, but slightly more attenuated and without + the extra bright effect that "delay 2" has near the source. "_color" "r g b" diff --git a/light/ltface.c b/light/ltface.c index 282e7c98..aa8e96d3 100644 --- a/light/ltface.c +++ b/light/ltface.c @@ -460,7 +460,9 @@ scaledDistance(vec_t distance, const entity_t *light) return scaledist * light->atten * distance; case LF_INVERSE: case LF_INVERSE2: + case LF_INVERSE2A: case LF_INFINITE: + case LF_LOCALMIN: /* Return a small distance to prevent culling these lights, since we */ /* know these formulae won't fade to nothing. */ return (distance <= 0.0) ? -0.25 : 0.25; @@ -472,20 +474,25 @@ scaledDistance(vec_t distance, const entity_t *light) static vec_t scaledLight(vec_t distance, const entity_t *light) { - const vec_t tmp = scaledist * light->atten * distance; + vec_t dist; - switch (light->formula) { - case LF_INFINITE: + if (light->formula == LF_INFINITE || light->formula == LF_LOCALMIN) return light->light; + + dist = scaledist * light->atten * distance; + switch (light->formula) { case LF_INVERSE: - return light->light / (tmp / LF_SCALE); + return light->light / (dist / LF_SCALE); + case LF_INVERSE2A: + dist += LF_SCALE; + /* Fall through */ case LF_INVERSE2: - return light->light / ((tmp * tmp) / (LF_SCALE * LF_SCALE)); + return light->light / ((dist * dist) / (LF_SCALE * LF_SCALE)); case LF_LINEAR: if (light->light > 0) - return (light->light - tmp > 0) ? light->light - tmp : 0; + return (light->light - dist > 0) ? light->light - dist : 0; else - return (light->light + tmp < 0) ? light->light + tmp : 0; + return (light->light + dist < 0) ? light->light + dist : 0; default: Error("Internal error: unknown light formula"); } @@ -722,9 +729,10 @@ SkyLightFace(lightinfo_t *l, const vec3_t faceoffset, const vec3_t colors) static void FixMinlight(lightinfo_t *l) { - int i, j; + int i, j, k; vec_t *lightmap; vec3_t *colormap; + const entity_t *entity; /* Find a style 0 lightmap */ lightmap = NULL; @@ -739,7 +747,7 @@ FixMinlight(lightinfo_t *l) if (!lightmap) { if (l->numlightstyles == MAXLIGHTMAPS) - return; /* oh well... */ + return; /* oh well... FIXME - should we warn? */ lightmap = l->lightmaps[l->numlightstyles]; for (i = 0; i < l->numsurfpt; i++) lightmap[i] = worldminlight; @@ -762,6 +770,50 @@ FixMinlight(lightinfo_t *l) } } } + + /* Cast rays for local minlight entities */ + for (i = 0, entity = entities; i < num_entities; i++, entity++) { + if (entity->formula != LF_LOCALMIN) + continue; + + /* Find the lightmap with correct style */ + lightmap = NULL; + colormap = NULL; + for (j = 0; j < l->numlightstyles; j++) { + if (l->lightstyles[j] == 0) { + lightmap = l->lightmaps[j]; + colormap = l->lightmapcolors[j]; + break; + } + } + if (!lightmap) { + if (l->numlightstyles == MAXLIGHTMAPS) + continue; /* oh well... FIXME - should we warn? */ + lightmap = l->lightmaps[l->numlightstyles]; + colormap = l->lightmapcolors[l->numlightstyles]; + l->numlightstyles++; + } + + for (j = 0; j < l->numsurfpt; j++) { + qboolean trace = false; + if (lightmap[j] < entity->light) { + trace = TestLine(entity->origin, l->surfpt[j]); + if (!trace) + continue; + lightmap[j] = entity->light; + } + if (!colored) + continue; + for (k = 0; k < 3; k++) { + if (colormap[j][k] < minlight_color[k]) { + if (!trace) + trace = TestLine(entity->origin, l->surfpt[j]); + if (trace) + colormap[j][k] = minlight_color[k]; + } + } + } + } } @@ -900,6 +952,8 @@ LightFace(int surfnum, qboolean nolight, const vec3_t faceoffset) if (nominlimit) { /* cast only positive lights */ for (i = 0, entity = entities; i < num_entities; i++, entity++) { + if (entity->formula == LF_LOCALMIN) + continue; if (colored) { if (entity->light) { PositiveColors(entity->light, colors, entity->lightcolor); @@ -920,10 +974,12 @@ LightFace(int surfnum, qboolean nolight, const vec3_t faceoffset) } } else { /* (!nominlimit) => cast all lights */ - for (i = 0, entity = entities; i < num_entities; i++, entity++) + for (i = 0, entity = entities; i < num_entities; i++, entity++) { + if (entity->formula == LF_LOCALMIN) + continue; if (entity->light) SingleLightFace(entity, &l, faceoffset, colors); - + } /* cast sky light */ if (sunlight) SkyLightFace(&l, faceoffset, colors); @@ -935,6 +991,8 @@ LightFace(int surfnum, qboolean nolight, const vec3_t faceoffset) if (nominlimit) { /* cast only negative lights */ for (i = 0, entity = entities; i < num_entities; i++, entity++) { + if (entity->formula == LF_LOCALMIN) + continue; if (colored) { if (entity->light) { NegativeColors(entity->light, colors, entity->lightcolor);