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 00cad9fda9..afc56902f6 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 @@ -336,14 +336,9 @@ private List calculateLitAreaForLightSource( final var p = FogUtil.calculateVisionCenter(lightSourceToken, zone); final var translateTransform = AffineTransform.getTranslateInstance(p.x, p.y); - final var magnifyTransform = AffineTransform.getScaleInstance(multiplier, multiplier); - final var lightSourceArea = lightSource.getArea(lightSourceToken, zone); // Calculate exposed area - // Jamz: OK, let not have lowlight vision type multiply darkness radius - if (multiplier != 1 && lightSource.getType() == LightSource.Type.NORMAL) { - lightSourceArea.transform(magnifyTransform); - } + final var lightSourceArea = lightSource.getArea(lightSourceToken, zone, multiplier); lightSourceArea.transform(translateTransform); Area lightSourceVisibleArea = lightSourceArea; @@ -365,35 +360,16 @@ private List calculateLitAreaForLightSource( final var litAreas = new ArrayList(); - // Tracks the cummulative inner ranges of light sources so that we can cut them out of the - // outer ranges and end up with disjoint sets, even when magnifying. - // Note that this "hole punching" has nothing to do with lumen strength, it's just a way of - // making smaller ranges act as lower bounds for larger ranges. - final var cummulativeNotTransformedArea = new Area(); - for (final var light : lightSource.getLightList()) { - final var notScaledLightArea = - light.getArea(lightSourceToken, zone, lightSource.isScaleWithToken()); - if (notScaledLightArea == null) { - continue; - } - final var lightArea = new Area(notScaledLightArea); - - // Lowlight vision does not magnify darkness. - if (multiplier != 1 - && lightSource.getType() == LightSource.Type.NORMAL - && light.getLumens() >= 0) { - lightArea.transform(magnifyTransform); - } + for (final var lightArea : lightSource.getLightAreas(lightSourceToken, zone, multiplier)) { + var area = lightArea.area(); + var light = lightArea.light(); - lightArea.subtract(cummulativeNotTransformedArea); - lightArea.transform(translateTransform); - lightArea.intersect(lightSourceVisibleArea); + area.transform(translateTransform); + area.intersect(lightSourceVisibleArea); litAreas.add( new ContributedLight( - new LitArea(light.getLumens(), lightArea), new LightInfo(lightSource, light))); - - cummulativeNotTransformedArea.add(notScaledLightArea); + new LitArea(light.getLumens(), area), new LightInfo(lightSource, light))); } // Magnification can cause different ranges for a single light source to overlap. This is not diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/VisionOverlayRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/VisionOverlayRenderer.java index c121d5695a..6b537da5ee 100644 --- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/VisionOverlayRenderer.java +++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/VisionOverlayRenderer.java @@ -68,7 +68,6 @@ public void render(Graphics2D g, PlayerView view, Token tokenUnderMouse) { private void renderWorld(Graphics2D worldG, PlayerView view, Token token) { // The vision of the token is not necessarily related to the current view. - // final var tokenView = view.derive(Collections.singleton(token)); final var tokenView = new PlayerView(view.getRole(), List.of(token)); Area currentTokenVisionArea = zoneView.getVisibleArea(token, tokenView); diff --git a/src/main/java/net/rptools/maptool/model/Grid.java b/src/main/java/net/rptools/maptool/model/Grid.java index 1f7b1090d0..087161543e 100644 --- a/src/main/java/net/rptools/maptool/model/Grid.java +++ b/src/main/java/net/rptools/maptool/model/Grid.java @@ -25,6 +25,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import javax.annotation.Nonnull; import javax.swing.Action; import javax.swing.KeyStroke; import net.rptools.lib.FileUtil; @@ -352,7 +353,7 @@ public void setSize(int size) { * @param scaleWithToken used to increase the area based on token footprint * @return Area */ - public Area getShapedArea( + public @Nonnull Area getShapedArea( ShapeType shape, Token token, double range, diff --git a/src/main/java/net/rptools/maptool/model/Light.java b/src/main/java/net/rptools/maptool/model/Light.java index 878e85bbae..f195fc8063 100644 --- a/src/main/java/net/rptools/maptool/model/Light.java +++ b/src/main/java/net/rptools/maptool/model/Light.java @@ -100,18 +100,28 @@ public double getArcAngle() { return shape; } - public @Nonnull Area getArea(@Nonnull Token token, @Nonnull Zone zone, boolean scaleWithToken) { + public @Nonnull Area getArea( + @Nonnull Token token, @Nonnull Zone zone, double multiplier, boolean scaleWithToken) { + var radius = getRadius(); + // Darkness does not get magnified. + if (lumens >= 0) { + radius *= multiplier; + } return zone.getGrid() .getShapedArea( getShape(), token, - getRadius(), + radius, getWidth(), getArcAngle(), (int) getFacingOffset(), scaleWithToken); } + public @Nonnull Area getArea(@Nonnull Token token, @Nonnull Zone zone, boolean scaleWithToken) { + return getArea(token, zone, 1.0, scaleWithToken); + } + public boolean isGM() { return isGM; } diff --git a/src/main/java/net/rptools/maptool/model/LightSource.java b/src/main/java/net/rptools/maptool/model/LightSource.java index 0c7830644a..619494ecbe 100644 --- a/src/main/java/net/rptools/maptool/model/LightSource.java +++ b/src/main/java/net/rptools/maptool/model/LightSource.java @@ -216,6 +216,50 @@ public boolean isIgnoresVBL() { return ignoresVBL; } + public record LightArea(Light light, Area area) {} + + public @Nonnull List getLightAreas( + @Nonnull Token token, @Nonnull Zone zone, double multiplier) { + // Tracks the cumulative inner ranges of light sources so that we can cut them out of the + // outer ranges and end up with disjoint sets, even when magnifying. + // Note that this "hole punching" has nothing to do with lumen strength, it's just a way of + // making smaller ranges act as lower bounds for larger ranges. + + // Auras do not get magnified. + if (type != Type.NORMAL) { + multiplier = 1.0; + } + + final var result = new ArrayList(); + final var cummulativeNotTransformedArea = new Area(); + + for (final var light : lightList) { + final var notScaledLightArea = light.getArea(token, zone, scaleWithToken); + + final var lightArea = light.getArea(token, zone, multiplier, scaleWithToken); + lightArea.subtract(cummulativeNotTransformedArea); + result.add(new LightArea(light, lightArea)); + + cummulativeNotTransformedArea.add(notScaledLightArea); + } + return result; + } + + /* Area for all lights combined */ + public @Nonnull Area getArea(@Nonnull Token token, @Nonnull Zone zone, double multiplier) { + // Auras do not get magnified. + if (type != Type.NORMAL) { + multiplier = 1.0; + } + + Area area = new Area(); + for (Light light : lightList) { + area.add(light.getArea(token, zone, multiplier, isScaleWithToken())); + } + + return area; + } + /* * Area for a single light, subtracting any previous lights */ @@ -232,12 +276,7 @@ public boolean isIgnoresVBL() { /* Area for all lights combined */ public @Nonnull Area getArea(@Nonnull Token token, @Nonnull Zone zone) { - Area area = new Area(); - for (Light light : lightList) { - area.add(light.getArea(token, zone, isScaleWithToken())); - } - - return area; + return getArea(token, zone, 1.0); } @SuppressWarnings("unchecked")