diff --git a/src/level/doomdata.h b/src/level/doomdata.h index 0e4cc28..750fbf1 100644 --- a/src/level/doomdata.h +++ b/src/level/doomdata.h @@ -223,6 +223,7 @@ struct IntThing char special; char args[5]; + short pitch; // UDMF float height; // UDMF TArray props; @@ -278,7 +279,8 @@ struct thingLight_t kexVec2 origin; kexVec3 rgb; float intensity; - float falloff; + float innerAngleCos; + float outerAngleCos; float height; float radius; bool bCeiling; diff --git a/src/level/level.cpp b/src/level/level.cpp index 9c69076..81229ae 100644 --- a/src/level/level.cpp +++ b/src/level/level.cpp @@ -130,6 +130,7 @@ void FProcessor::LoadThings () Level.Things[i].args[2] = Things[i].args[2]; Level.Things[i].args[3] = Things[i].args[3]; Level.Things[i].args[4] = Things[i].args[4]; + Level.Things[i].pitch = 0; } delete[] Things; } @@ -153,6 +154,7 @@ void FProcessor::LoadThings () Level.Things[i].args[2] = 0; Level.Things[i].args[3] = 0; Level.Things[i].args[4] = 0; + Level.Things[i].pitch = 0; } delete[] mt; } diff --git a/src/level/level_udmf.cpp b/src/level/level_udmf.cpp index 2055a15..8de21af 100644 --- a/src/level/level_udmf.cpp +++ b/src/level/level_udmf.cpp @@ -158,6 +158,8 @@ fixed_t CheckFixed(const char *key) void FProcessor::ParseThing(IntThing *th) { + th->pitch = 0; + SC_MustGetStringName("{"); while (!SC_CheckString("}")) { @@ -179,6 +181,10 @@ void FProcessor::ParseThing(IntThing *th) { th->angle = (short)CheckInt(key); } + if (!stricmp(key, "pitch")) + { + th->pitch = (short)CheckInt(key); + } if (!stricmp(key, "type")) { th->type = (short)CheckInt(key); diff --git a/src/lightmap/lightmap.cpp b/src/lightmap/lightmap.cpp index 4d4f3f5..58d9aa7 100644 --- a/src/lightmap/lightmap.cpp +++ b/src/lightmap/lightmap.cpp @@ -238,19 +238,22 @@ bool kexLightmapBuilder::EmitFromCeiling(kexTrace &trace, const surface_t *surfa // and against all nearby thing lights // +template +T smoothstep(const T edge0, const T edge1, const T x) +{ + auto t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +static float radians(float degrees) +{ + return degrees * 3.14159265359f / 180.0f; +} + kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &origin, surface_t *surface) { - kexVec3 lightOrigin; - kexVec3 dir; - kexVec3 color; - kexPlane plane; - float dist; - float radius; - float intensity; - float colorAdd; - - plane = surface->plane; - color.Clear(); + kexPlane plane = surface->plane; + kexVec3 color(0.0f, 0.0f, 0.0f); // check all thing lights for(unsigned int i = 0; i < map->thingLights.Size(); i++) @@ -263,11 +266,13 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori continue; } - lightOrigin.Set(tl->origin.x, - tl->origin.y, - !tl->bCeiling ? - tl->sector->data.floorheight + tl->height : - tl->sector->data.ceilingheight - tl->height); + float originZ; + if (!tl->bCeiling) + originZ = tl->sector->floorplane.zAt(tl->origin.x, tl->origin.y) + tl->height; + else + originZ = tl->sector->ceilingplane.zAt(tl->origin.x, tl->origin.y) - tl->height; + + kexVec3 lightOrigin(tl->origin.x, tl->origin.y, originZ); if(plane.Distance(lightOrigin) - plane.d < 0) { @@ -275,8 +280,8 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori continue; } - radius = tl->radius; - intensity = tl->intensity; + float radius = tl->radius; + float intensity = tl->intensity; if(origin.DistanceSq(lightOrigin) > (radius*radius)) { @@ -284,6 +289,28 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori continue; } + kexVec3 dir = (lightOrigin - origin); + float dist = dir.Unit(); + dir.Normalize(); + + float spotAttenuation = 1.0f; + if (tl->outerAngleCos > -1.0f) + { + float negPitch = -radians(tl->mapThing->pitch); + float xyLen = std::cosf(negPitch); + kexVec3 spotDir; + spotDir.x = std::sinf(radians(tl->mapThing->angle)) * xyLen; + spotDir.y = std::cosf(radians(tl->mapThing->angle)) * xyLen; + spotDir.z = -std::sinf(negPitch); + float cosDir = kexVec3::Dot(dir, spotDir); + spotAttenuation = smoothstep(tl->outerAngleCos, tl->innerAngleCos, cosDir); + if (spotAttenuation <= 0.0f) + { + // outside spot light + continue; + } + } + trace.Trace(lightOrigin, origin); if(trace.fraction != 1) @@ -292,23 +319,13 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori continue; } - dir = (lightOrigin - origin); - dist = dir.Unit(); - - dir.Normalize(); - - float r = MAX(radius - dist, 0.0f); - - colorAdd = ((r * plane.Normal().Dot(dir)) / radius) * intensity; - kexMath::Clamp(colorAdd, 0, 1); - - if(tl->falloff != 1) - { - colorAdd = kexMath::Pow(colorAdd, tl->falloff); - } + float attenuation = 1.0f - (dist / radius); + attenuation *= spotAttenuation; + attenuation *= plane.Normal().Dot(dir); + attenuation *= intensity; // accumulate results - color += tl->rgb * colorAdd; + color += tl->rgb * attenuation; tracedTexels++; } @@ -331,9 +348,10 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori continue; } - if(surfaceLight->TraceSurface(map, trace, surface, origin, &dist)) + float attenuation; + if(surfaceLight->TraceSurface(map, trace, surface, origin, &attenuation)) { - color += surfaceLight->GetRGB() * kexMath::Pow(dist * surfaceLight->Intensity(), surfaceLight->FallOff()); + color += surfaceLight->GetRGB() * attenuation; tracedTexels++; } diff --git a/src/lightmap/lightsurface.cpp b/src/lightmap/lightsurface.cpp index 8e3402f..1a07bb1 100644 --- a/src/lightmap/lightsurface.cpp +++ b/src/lightmap/lightsurface.cpp @@ -302,7 +302,7 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa // light surface will always be fullbright if(surf == surface) { - *dist = 1; + *dist = Intensity(); return true; } @@ -426,7 +426,7 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa if(!bWall) { *dist = 1; - return true; + break; } } @@ -451,5 +451,6 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa } } + *dist *= Intensity(); return *dist > 0; } diff --git a/src/lightmap/mapdata.cpp b/src/lightmap/mapdata.cpp index b8451b7..a0613f1 100644 --- a/src/lightmap/mapdata.cpp +++ b/src/lightmap/mapdata.cpp @@ -450,6 +450,8 @@ void FLevel::CreateLights() uint32_t lightcolor = 0xffffff; float lightintensity = 1.0f; float lightdistance = 0.0f; + float innerAngleCos = -1.0f; + float outerAngleCos = -1.0f; for (unsigned int propIndex = 0; propIndex < thing->props.Size(); propIndex++) { @@ -466,6 +468,14 @@ void FLevel::CreateLights() { lightdistance = atof(key.value); } + else if (!stricmp(key.key, "lightinnerangle")) + { + innerAngleCos = std::cosf(atof(key.value) * 3.14159265359f / 180.0f); + } + else if (!stricmp(key.key, "lightouterangle")) + { + outerAngleCos = std::cosf(atof(key.value) * 3.14159265359f / 180.0f); + } } if (lightdistance > 0.0f && lightintensity > 0.0f && lightcolor != 0) @@ -480,7 +490,8 @@ void FLevel::CreateLights() thingLight->rgb.y = ((lightcolor >> 8) & 0xff) / 255.0f; thingLight->rgb.z = (lightcolor & 0xff) / 255.0f; thingLight->intensity = lightintensity; - thingLight->falloff = 1.0f; + thingLight->innerAngleCos = max(innerAngleCos, outerAngleCos); + thingLight->outerAngleCos = outerAngleCos; thingLight->radius = lightdistance; thingLight->height = thing->height; thingLight->bCeiling = false;