From 064937a7b0112566c2c252c5bcd778dc95c28101 Mon Sep 17 00:00:00 2001 From: Kenneth VanderLinde Date: Wed, 18 Sep 2024 16:43:52 -0700 Subject: [PATCH] Restrict each drawable light to its lumens level (overtop lighting) Environmental lighting continues to allow overlap between lumens levels as these are meant to be more natural and less mechanical regarding their rendering. --- .../maptool/client/ui/zone/Illumination.java | 18 +++++++++ .../maptool/client/ui/zone/ZoneView.java | 37 +++++++++++++++---- .../java/net/rptools/maptool/model/Zone.java | 2 + .../model/zones/ZoneLightingChanged.java | 19 ++++++++++ 4 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 src/main/java/net/rptools/maptool/model/zones/ZoneLightingChanged.java diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/Illumination.java b/src/main/java/net/rptools/maptool/client/ui/zone/Illumination.java index b32d135b71..c2f2c1ae05 100644 --- a/src/main/java/net/rptools/maptool/client/ui/zone/Illumination.java +++ b/src/main/java/net/rptools/maptool/client/ui/zone/Illumination.java @@ -173,6 +173,24 @@ public Optional getObscuredLumensLevel(int lumensStrength) { return Collections.unmodifiableList(this.obscuredLumensLevels); } + /** + * Look up a disjoint obscured lumens level based on the lumens strength. + * + *

This is useful for rendering individual lights, so that the light can be constrained to the + * area that is actually illuminated by the light and not by any stronger light. + * + *

See {@link #getDisjointObscuredLumensLevels()} for more information. + * + * @param lumensStrength The strength of lumens to find. + * @return The {#link LumensLevel} of strength {@code lumensStrength}. If no level exists for it, + * an empty optional is returned. + */ + public Optional getDisjointObscuredLumensLevel(int lumensStrength) { + return getDisjointObscuredLumensLevels().stream() + .filter(level -> level.lumensStrength() == lumensStrength) + .findFirst(); + } + /** * Get the disjoint obscured lumens levels. * diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java b/src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java index afc56902f6..2933e75457 100644 --- a/src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java +++ b/src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java @@ -39,6 +39,7 @@ import net.rptools.maptool.model.zones.TokensChanged; import net.rptools.maptool.model.zones.TokensRemoved; import net.rptools.maptool.model.zones.TopologyChanged; +import net.rptools.maptool.model.zones.ZoneLightingChanged; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -724,6 +725,8 @@ public Collection getDrawableLights(PlayerView view) { drawableLights.computeIfAbsent( view, view2 -> { + final var lightingStyle = zone.getLightingStyle(); + final var illuminationKey = illuminationKeyFromView(view2); final var illuminationModel = getIlluminationModel(illuminationKey); @@ -755,9 +758,16 @@ public Collection getDrawableLights(PlayerView view) { // Make sure each drawable light is restricted to the area it covers, // accounting for darkness effects. final var obscuredArea = new Area(laud.litArea().area()); + + final var lumensStrength = Math.abs(laud.litArea().lumens()); final var lumensLevel = - illumination.getObscuredLumensLevel(Math.abs(laud.litArea().lumens())); - // Should always be present based on construction, but just in case. + switch (lightingStyle) { + case ENVIRONMENTAL -> illumination.getObscuredLumensLevel( + lumensStrength); + case OVERTOP -> illumination.getDisjointObscuredLumensLevel( + lumensStrength); + }; + // Should always be present based on construction, but just in case... if (lumensLevel.isEmpty()) { return null; } @@ -794,14 +804,18 @@ public void flush() { exposedAreaMap.clear(); visibleAreaMap.clear(); - drawableLights.clear(); - drawableAuras.clear(); + flushLights(); } public void flushFog() { exposedAreaMap.clear(); } + private void flushLights() { + drawableLights.clear(); + drawableAuras.clear(); + } + /** * Flush the ZoneView cache of the token. Remove token from {@link #tokenVisionCachePerView}, and * {@link #illuminationModels}. Can clear {@link #tokenVisionCachePerView}, {@link @@ -860,6 +874,15 @@ private void onTopologyChanged(TopologyChanged event) { topologyTrees.clear(); } + @Subscribe + private void onZoneLightingChanged(ZoneLightingChanged event) { + if (event.zone() != this.zone) { + return; + } + + flushLights(); + } + private boolean flushExistingTokens(List tokens) { boolean tokenChangedTopology = false; for (Token token : tokens) { @@ -896,8 +919,7 @@ private void onTokensRemoved(TokensRemoved event) { } if (anyLightingChanges) { - drawableLights.clear(); - drawableAuras.clear(); + flushLights(); } if (event.tokens().stream().anyMatch(Token::hasAnyTopology)) { @@ -963,8 +985,7 @@ private void updateLightSourcesFromTokens(Iterable tokens) { } if (anyLightingChanges) { - drawableLights.clear(); - drawableAuras.clear(); + flushLights(); } } } diff --git a/src/main/java/net/rptools/maptool/model/Zone.java b/src/main/java/net/rptools/maptool/model/Zone.java index b54ae55787..e4c771bb28 100644 --- a/src/main/java/net/rptools/maptool/model/Zone.java +++ b/src/main/java/net/rptools/maptool/model/Zone.java @@ -61,6 +61,7 @@ import net.rptools.maptool.model.zones.TokensChanged; import net.rptools.maptool.model.zones.TokensRemoved; import net.rptools.maptool.model.zones.TopologyChanged; +import net.rptools.maptool.model.zones.ZoneLightingChanged; import net.rptools.maptool.server.Mapper; import net.rptools.maptool.server.proto.DrawnElementListDto; import net.rptools.maptool.server.proto.TopologyTypeDto; @@ -515,6 +516,7 @@ public LightingStyle getLightingStyle() { public void setLightingStyle(LightingStyle lightingStyle) { this.lightingStyle = lightingStyle; + new MapToolEventBus().getMainEventBus().post(new ZoneLightingChanged(this)); } public TokenSelection getTokenSelection() { diff --git a/src/main/java/net/rptools/maptool/model/zones/ZoneLightingChanged.java b/src/main/java/net/rptools/maptool/model/zones/ZoneLightingChanged.java new file mode 100644 index 0000000000..1f7a46bdf7 --- /dev/null +++ b/src/main/java/net/rptools/maptool/model/zones/ZoneLightingChanged.java @@ -0,0 +1,19 @@ +/* + * This software Copyright by the RPTools.net development team, and + * licensed under the Affero GPL Version 3 or, at your option, any later + * version. + * + * MapTool Source Code is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public + * License * along with this source Code. If not, please visit + * and specifically the Affero license + * text at . + */ +package net.rptools.maptool.model.zones; + +import net.rptools.maptool.model.Zone; + +public record ZoneLightingChanged(Zone zone) {}