From 978d5db8fd61ea8fe9e27e02ec756d66202ea112 Mon Sep 17 00:00:00 2001
From: bubblobill <45483160+bubblobill@users.noreply.github.com>
Date: Sun, 3 Aug 2025 00:47:44 +0800
Subject: [PATCH 1/8] LabelRenderer - Moved caches to class, added setters and
static isLabelVisible method. - Moved token label generation in token
rendering sequence preparatory to moving it out to DecorationRenderer. New
class TokenDecorationRenderer - Paints things before and after token
rendering. - Hub for halos, bars, states, etc. More bits to follow. New
class OverlayRenderer - For painting states and bars. FacingArrowRenderer -
Facing arrow now follows grid cell shape. Made some variables non-local.
GeometryUtil - Added functions for finding intersection points. HaloRenderer
- Now honours preference for opacity. TokenRenderer - Updated to call
decoration renderer before and after painting image. plus other tweaks.
ZoneViewModel - Added method- isUsingVision(). ZoneRenderer - Inverted
hasMoveSelectionSetMoved(). - Made imageLabelFactory a constant. -
LabelRenderingCache offloaded to LabelRenderer. - Renamed renderLabels()
method as it is confusing. - Removed redundant image loading and token
flipping from renderTokens(). - Other housework.
---
.../java/net/rptools/lib/GeometryUtil.java | 80 +++--
.../maptool/client/tool/PointerTool.java | 2 +-
.../maptool/client/tool/StampTool.java | 2 +-
.../maptool/client/ui/zone/ZoneViewModel.java | 4 +
.../client/ui/zone/renderer/HaloRenderer.java | 29 +-
.../client/ui/zone/renderer/ItemRenderer.java | 2 +-
.../ui/zone/renderer/LabelRenderer.java | 57 +++-
.../client/ui/zone/renderer/ZoneRenderer.java | 277 +++++++-----------
.../tokenRender/FacingArrowRenderer.java | 90 ++++--
.../renderer/tokenRender/OverlayRenderer.java | 103 +++++++
.../tokenRender/TokenDecorationRenderer.java | 80 +++++
.../renderer/tokenRender/TokenRenderer.java | 40 ++-
.../rptools/maptool/util/GraphicsUtil.java | 2 +-
13 files changed, 528 insertions(+), 240 deletions(-)
create mode 100644 src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java
create mode 100644 src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenDecorationRenderer.java
diff --git a/common/src/main/java/net/rptools/lib/GeometryUtil.java b/common/src/main/java/net/rptools/lib/GeometryUtil.java
index a77e46e61e..4a2010cf36 100644
--- a/common/src/main/java/net/rptools/lib/GeometryUtil.java
+++ b/common/src/main/java/net/rptools/lib/GeometryUtil.java
@@ -16,29 +16,17 @@
import java.awt.Shape;
import java.awt.geom.Area;
+import java.awt.geom.Line2D;
+import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.locationtech.jts.algorithm.InteriorPointArea;
import org.locationtech.jts.algorithm.Orientation;
import org.locationtech.jts.algorithm.PointLocation;
import org.locationtech.jts.awt.ShapeReader;
-import org.locationtech.jts.geom.Coordinate;
-import org.locationtech.jts.geom.CoordinateArrays;
-import org.locationtech.jts.geom.Envelope;
-import org.locationtech.jts.geom.Geometry;
-import org.locationtech.jts.geom.GeometryFactory;
-import org.locationtech.jts.geom.LinearRing;
-import org.locationtech.jts.geom.Location;
-import org.locationtech.jts.geom.MultiPolygon;
-import org.locationtech.jts.geom.Polygon;
-import org.locationtech.jts.geom.PrecisionModel;
+import org.locationtech.jts.geom.*;
import org.locationtech.jts.geom.util.GeometryFixer;
import org.locationtech.jts.operation.valid.IsValidOp;
import org.locationtech.jts.precision.GeometryPrecisionReducer;
@@ -91,8 +79,8 @@ public static Area union(Collection areas) {
}
/**
- * Like {@link #union(java.util.Collection)}, but will modify the areas and collection for
- * performance gains.
+ * Like {@link #union(Collection)}, but will modify the areas and collection for performance
+ * gains.
*
* @param areas The areas to union.
* @return The union of {@code areas}
@@ -137,6 +125,62 @@ public static MultiPolygon toJts(Shape shape) {
return geometry;
}
+ /**
+ * Use for a simple shape that is a closed polygon without holes.
+ *
+ * @param shape a closed polygon
+ * @return LinearRing geometry
+ */
+ public static LinearRing shapeToLinearRing(Shape shape) {
+ List coordinates = new ArrayList<>();
+ final PathIterator iterator = shape.getPathIterator(null);
+ final double[] pathCoordinate = new double[2];
+ iterator.currentSegment(pathCoordinate);
+ coordinates.add(new CoordinateXY(pathCoordinate[0], pathCoordinate[1]));
+ iterator.next();
+ while (!iterator.isDone()) {
+ iterator.currentSegment(pathCoordinate);
+ coordinates.add(new CoordinateXY(pathCoordinate[0], pathCoordinate[1]));
+ iterator.next();
+ }
+ coordinates.add(coordinates.getFirst()); // close the polygon
+ return getGeometryFactory().createLinearRing(coordinates.toArray(Coordinate[]::new));
+ }
+
+ /**
+ * Converts a line2D to the jts geometry LinearString
+ *
+ * @param line2D line to convert
+ * @return LinearString geometry
+ */
+ public static LineString line2DToLinearString(final Line2D line2D) {
+ return getGeometryFactory()
+ .createLineString(
+ new Coordinate[] {
+ GeometryUtil.point2DToCoordinate(line2D.getP1()),
+ GeometryUtil.point2DToCoordinate(line2D.getP2())
+ });
+ }
+
+ /**
+ * Find the points of intersection between a line and a shape
+ *
+ * @param line the intersecting line
+ * @param shape the shape to intersect
+ * @return Array of intersecting points
+ */
+ public static Point2D[] lineSegmentShapeIntersection(final Line2D line, final Shape shape) {
+ LineString lineString = line2DToLinearString(line);
+ LinearRing linearRing = shapeToLinearRing(shape);
+ Geometry intersection = lineString.intersection(linearRing);
+ if (intersection.getNumPoints() > 0) {
+ return Arrays.stream(intersection.getCoordinates())
+ .map(GeometryUtil::coordinateToPoint2D)
+ .toArray(Point2D[]::new);
+ }
+ return new Point2D.Double[] {};
+ }
+
public static Collection toJtsPolygons(Shape shape) {
if (shape instanceof Area area && area.isEmpty()) {
return Collections.emptyList();
diff --git a/src/main/java/net/rptools/maptool/client/tool/PointerTool.java b/src/main/java/net/rptools/maptool/client/tool/PointerTool.java
index 30cda463fa..c513158b2c 100644
--- a/src/main/java/net/rptools/maptool/client/tool/PointerTool.java
+++ b/src/main/java/net/rptools/maptool/client/tool/PointerTool.java
@@ -1831,7 +1831,7 @@ private void doDragTo(ZonePoint newAnchorPoint) {
}
// Don't bother if there isn't any movement
- if (!renderer.hasMoveSelectionSetMoved(tokenBeingDragged.getId(), newAnchorPoint)) {
+ if (renderer.isMoveSelectionSetUnchanged(tokenBeingDragged.getId(), newAnchorPoint)) {
return;
}
diff --git a/src/main/java/net/rptools/maptool/client/tool/StampTool.java b/src/main/java/net/rptools/maptool/client/tool/StampTool.java
index 82730e8853..e33c649662 100644
--- a/src/main/java/net/rptools/maptool/client/tool/StampTool.java
+++ b/src/main/java/net/rptools/maptool/client/tool/StampTool.java
@@ -1206,7 +1206,7 @@ public void moveByKey(int dx, int dy, boolean micro) {
private void doDragTo(ZonePoint newAnchorPoint) {
// Don't bother if there isn't any movement
- if (!renderer.hasMoveSelectionSetMoved(tokenBeingDragged.getId(), newAnchorPoint)) {
+ if (renderer.isMoveSelectionSetUnchanged(tokenBeingDragged.getId(), newAnchorPoint)) {
return;
}
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/ZoneViewModel.java b/src/main/java/net/rptools/maptool/client/ui/zone/ZoneViewModel.java
index a836cb51cb..f1ef1bb20b 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/ZoneViewModel.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/ZoneViewModel.java
@@ -161,6 +161,10 @@ public Rectangle2D getViewport() {
viewport.getMinX(), viewport.getMinY(), viewport.getWidth(), viewport.getHeight());
}
+ public boolean isUsingVision() {
+ return zoneView.isUsingVision();
+ }
+
public Area getVisibleArea() {
return visibleArea;
}
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/HaloRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/HaloRenderer.java
index f48b5dbf56..cb66277222 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/HaloRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/HaloRenderer.java
@@ -30,6 +30,13 @@
public class HaloRenderer {
private final RenderHelper renderHelper;
private final Zone zone;
+ private float opacity = AppPreferences.haloOverlayOpacity.get() / 255f;
+ private float lineWeight = AppPreferences.haloLineWidth.get();
+
+ {
+ AppPreferences.haloOverlayOpacity.onChange(i -> opacity = i / 255f);
+ AppPreferences.haloLineWidth.onChange(i -> lineWeight = i);
+ }
// region These fields need to be recalculated whenever the grid changes.
@@ -69,16 +76,15 @@ private Shape getHaloShape(Grid grid) {
.createTransformedShape(cachedHaloShape);
}
}
-
return cachedHaloShape;
}
// Render Halos
- public void renderHalo(Graphics2D g2d, Token token, ZoneViewModel.TokenPosition position) {
+ public void renderHalo(Graphics2D g2d, ZoneViewModel.TokenPosition position) {
+ Token token = position.token();
if (token.getHaloColor() == null) {
return;
}
-
var grid = zone.getGrid();
if (grid == null) {
return;
@@ -105,29 +111,32 @@ public void renderHalo(Graphics2D g2d, Token token, ZoneViewModel.TokenPosition
position.transformedBounds().getBounds2D().getCenterX(),
position.transformedBounds().getBounds2D().getCenterY())
.createTransformedShape(paintShape);
-
// this will eventually hold forks for painting different types of halo
renderHelper.render(
g2d,
worldG -> {
- paintLineHalo(worldG, token, grid, positionedPaintShape);
+ paintLineHalo(worldG, position.token(), grid, positionedPaintShape);
});
}
private void paintLineHalo(Graphics2D g2d, Token token, Grid grid, Shape paintShape) {
+ Stroke oldStroke = g2d.getStroke();
+ g2d.setColor(token.getHaloColor());
// double width because we will clip the inside half
g2d.setStroke(
new BasicStroke(
- (float)
- (2f
- * Math.min(1f, token.getFootprint(grid).getScale())
- * AppPreferences.haloLineWidth.get())));
- g2d.setColor(token.getHaloColor());
+ (float) (2f * lineWeight * Math.min(1f, token.getFootprint(grid).getScale()))));
Shape oldClip = g2d.getClip();
+ Composite oldComposite = g2d.getComposite();
+ if (opacity < 1f) {
+ g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
+ }
Area a = new Area(g2d.getClipBounds());
a.subtract(new Area(paintShape));
g2d.setClip(a);
g2d.draw(paintShape);
g2d.setClip(oldClip);
+ g2d.setComposite(oldComposite);
+ g2d.setStroke(oldStroke);
}
}
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ItemRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ItemRenderer.java
index 9fa98abd4e..4b31ac4c0b 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ItemRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ItemRenderer.java
@@ -16,7 +16,7 @@
import java.awt.*;
-interface ItemRenderer {
+public interface ItemRenderer {
public void render(Graphics2D g);
}
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/LabelRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/LabelRenderer.java
index 598e0c4be6..e3f1aa85a6 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/LabelRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/LabelRenderer.java
@@ -16,18 +16,34 @@
import java.awt.*;
import java.awt.image.BufferedImage;
+import java.util.HashMap;
+import java.util.Map;
import javax.swing.*;
+import net.rptools.maptool.client.AppState;
+import net.rptools.maptool.client.MapTool;
import net.rptools.maptool.client.swing.ImageLabel;
+import net.rptools.maptool.client.ui.zone.ZoneViewModel;
import net.rptools.maptool.model.GUID;
import net.rptools.maptool.util.GraphicsUtil;
/** Represents a delayed label render */
-class LabelRenderer implements ItemRenderer {
+public class LabelRenderer implements ItemRenderer {
+
+ private static final Map labelCache = new HashMap<>();
+ private static final Map labelImageCache = new HashMap<>();
+
+ public static Map getLabelCache() {
+ return labelCache;
+ }
+
+ public static Map getLabelImageCache() {
+ return labelImageCache;
+ }
private final ZoneRenderer renderer;
private final String text;
private int x;
- private final int y;
+ private int y;
private final int align;
private final Color foreground;
private final ImageLabel background;
@@ -52,8 +68,8 @@ public LabelRenderer(ZoneRenderer renderer, String text, int x, int y, GUID tId)
this.foreground = Color.black;
tokenId = tId;
if (tokenId != null) {
- width = renderer.labelRenderingCache.get(tokenId).getWidth();
- height = renderer.labelRenderingCache.get(tokenId).getHeight();
+ width = labelImageCache.get(tokenId).getWidth();
+ height = labelImageCache.get(tokenId).getHeight();
}
}
@@ -87,11 +103,22 @@ public LabelRenderer(
this.background = background;
tokenId = tId;
if (tokenId != null) {
- width = renderer.labelRenderingCache.get(tokenId).getWidth();
- height = renderer.labelRenderingCache.get(tokenId).getHeight();
+ width = labelImageCache.get(tokenId).getWidth();
+ height = labelImageCache.get(tokenId).getHeight();
}
}
+ public static boolean isLabelVisible(
+ ZoneViewModel.TokenPosition position, ZoneViewModel viewModel, boolean hover) {
+ if (!(AppState.isShowTokenNames() || hover)) {
+ return false;
+ }
+ // if policy does not auto-reveal FoW, check if fog covers the token (slow)
+ return viewModel.getPlayerView().isGMView()
+ || (viewModel.isUsingVision() && MapTool.getServerPolicy().isAutoRevealOnMovement())
+ || viewModel.zone.isTokenVisible(position.token());
+ }
+
public void render(Graphics2D g) {
if (tokenId != null) { // Use cached image.
switch (align) {
@@ -104,7 +131,7 @@ public void render(Graphics2D g) {
case SwingUtilities.LEFT:
break;
}
- BufferedImage img = renderer.labelRenderingCache.get(tokenId);
+ BufferedImage img = labelImageCache.get(tokenId);
if (img != null) {
g.drawImage(img, x, y, width, height, null);
} else { // Draw as normal
@@ -114,4 +141,20 @@ public void render(Graphics2D g) {
GraphicsUtil.drawBoxedString(g, text, x, y, align, background, foreground);
}
}
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public void setX(int x) {
+ this.x = x;
+ }
+
+ public void setY(int y) {
+ this.y = y;
+ }
}
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ZoneRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ZoneRenderer.java
index 544ac2c42a..e1db482b72 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ZoneRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ZoneRenderer.java
@@ -28,6 +28,7 @@
import java.awt.font.TextLayout;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
+import java.io.Serial;
import java.text.NumberFormat;
import java.util.*;
import java.util.List;
@@ -51,12 +52,10 @@
import net.rptools.maptool.client.ui.Scale;
import net.rptools.maptool.client.ui.theme.Images;
import net.rptools.maptool.client.ui.theme.RessourceManager;
-import net.rptools.maptool.client.ui.token.AbstractTokenOverlay;
-import net.rptools.maptool.client.ui.token.BarTokenOverlay;
import net.rptools.maptool.client.ui.token.dialog.create.NewTokenDialog;
import net.rptools.maptool.client.ui.zone.*;
import net.rptools.maptool.client.ui.zone.gdx.GdxRenderer;
-import net.rptools.maptool.client.ui.zone.renderer.tokenRender.FacingArrowRenderer;
+import net.rptools.maptool.client.ui.zone.renderer.tokenRender.TokenDecorationRenderer;
import net.rptools.maptool.client.ui.zone.renderer.tokenRender.TokenRenderer;
import net.rptools.maptool.client.walker.ZoneWalker;
import net.rptools.maptool.events.MapToolEventBus;
@@ -69,16 +68,17 @@
import net.rptools.maptool.model.zones.*;
import net.rptools.maptool.util.GraphicsUtil;
import net.rptools.maptool.util.ImageManager;
-import net.rptools.maptool.util.ImageSupport;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** */
public class ZoneRenderer extends JComponent implements DropTargetListener {
- private static final long serialVersionUID = 3832897780066104884L;
+ @Serial private static final long serialVersionUID = 3832897780066104884L;
private static final Logger log = LogManager.getLogger(ZoneRenderer.class);
+ private static final FlatImageLabelFactory IMAGE_LABEL_FACTORY = new FlatImageLabelFactory();
+
/** DebounceExecutor for throttling repaint() requests. */
private final DebounceExecutor repaintDebouncer;
@@ -109,9 +109,7 @@ public class ZoneRenderer extends JComponent implements DropTargetListener {
private final List showPathList = new ArrayList<>();
// Optimizations
- final Map labelRenderingCache = new HashMap<>();
private Token tokenUnderMouse;
-
private ScreenPoint pointUnderMouse;
private @Nonnull Zone.Layer activeLayer = Layer.getDefaultPlayerLayer();
@@ -134,9 +132,8 @@ public class ZoneRenderer extends JComponent implements DropTargetListener {
private final EnumSet disabledLayers = EnumSet.noneOf(Layer.class);
private final GridRenderer gridRenderer;
- private final HaloRenderer haloRenderer;
private final TokenRenderer tokenRenderer;
- private final FacingArrowRenderer facingArrowRenderer;
+ private final TokenDecorationRenderer decorationRenderer;
private final SelectionRenderer selectionRenderer;
private final LightsRenderer lightsRenderer;
private final DarknessRenderer darknessRenderer;
@@ -159,20 +156,20 @@ public ZoneRenderer(Zone zone) {
throw new IllegalArgumentException("Zone cannot be null");
}
this.zone = zone;
- selectionModel = new SelectionModel(zone);
- zoneView = new ZoneView(zone);
+ this.selectionModel = new SelectionModel(zone);
+ this.zoneView = new ZoneView(zone);
this.viewModel = new ZoneViewModel(zone, zoneView, selectionModel);
setZoneScale(new Scale());
- drawableRenderers =
+ this.drawableRenderers =
CollectionUtil.newFilledEnumMap(
Zone.Layer.class, layer -> new PartitionedDrawableRenderer(zone));
var renderHelper = new RenderHelper(this, tempBufferPool);
this.gridRenderer = new GridRenderer(this);
- this.haloRenderer = new HaloRenderer(renderHelper, zone);
+
this.tokenRenderer = new TokenRenderer(renderHelper, zone);
- this.facingArrowRenderer = new FacingArrowRenderer(renderHelper, zone);
+ this.decorationRenderer = new TokenDecorationRenderer(renderHelper, zone);
this.selectionRenderer = new SelectionRenderer(renderHelper, viewModel, zoneView);
this.lightsRenderer = new LightsRenderer(renderHelper, zone, zoneView);
this.darknessRenderer = new DarknessRenderer(renderHelper, zoneView);
@@ -180,7 +177,7 @@ public ZoneRenderer(Zone zone) {
this.fogRenderer = new FogRenderer(renderHelper, zone, zoneView);
this.visionOverlayRenderer = new VisionOverlayRenderer(renderHelper, zone, zoneView);
this.debugRenderer = new DebugRenderer(renderHelper);
- repaintDebouncer =
+ this.repaintDebouncer =
new DebounceExecutor(1000 / AppPreferences.frameRateCap.get(), this::repaint);
setFocusable(true);
@@ -301,7 +298,7 @@ public void setMouseOver(Token token) {
if (tokenUnderMouse == token) {
return;
}
- tokenUnderMouse = token;
+ this.tokenUnderMouse = token;
repaintDebouncer.dispatch();
}
@@ -324,13 +321,13 @@ public void addMoveSelectionSet(String playerId, GUID keyToken, Set tokenL
return set.getKeyTokenDragAnchorPosition();
}
- public boolean hasMoveSelectionSetMoved(GUID keyToken, ZonePoint dragAnchorPosition) {
+ public boolean isMoveSelectionSetUnchanged(GUID keyToken, ZonePoint dragAnchorPosition) {
SelectionSet set = selectionSetMap.get(keyToken);
if (set == null) {
- return false;
+ return true;
}
- return !set.getKeyTokenDragAnchorPosition().equals(dragAnchorPosition);
+ return set.getKeyTokenDragAnchorPosition().equals(dragAnchorPosition);
}
public void updateMoveSelectionSet(GUID keyToken, ZonePoint latestPoint) {
@@ -546,15 +543,13 @@ public void centerOn(CellPoint point) {
}
/**
- * Remove the token from: {@link #labelRenderingCache}. Set the {@link #visibleScreenArea} to
- * null. Flush the token from {@link #zoneView}.
+ * Set the {@link #visibleScreenArea} to null. Flush the token from {@link #zoneView}.
*
* @param token the token to flush
*/
public void flush(Token token) {
// This method can be called from a non-EDT thread so if that happens, make sure we synchronize
// with the EDT.
- labelRenderingCache.remove(token.getId());
// This should be smarter, but whatever
visibleScreenArea = null;
@@ -676,8 +671,8 @@ public void enforceView(int x, int y, double scale, int gmWidth, int gmHeight) {
}
public void restoreView() {
- log.info("Restoring view: " + previousZonePoint);
- log.info("previousScale: " + previousScale);
+ log.info("Restoring view: {}", previousZonePoint);
+ log.info("previousScale: {}", previousScale);
centerOn(previousZonePoint);
setScale(previousScale);
@@ -979,7 +974,7 @@ public void renderZone(Graphics2D g2d, @Nullable PlayerView view) {
// (This method has its own 'timer' calls)
if (AppState.getShowTextLabels()) {
- renderLabels(g2d, view);
+ renderMapLabels(g2d, view);
}
this.fogRenderer.render(g2d, view);
@@ -1010,12 +1005,10 @@ public void renderZone(Graphics2D g2d, @Nullable PlayerView view) {
showBlockedMoves(g2d, view, getOwnedMovementSet(view));
timer.stop("owned movement");
- // Text associated with tokens being moved is added to a list to be drawn after, i.e. on top
- // of, the tokens themselves.
- // So if one moving token is on top of another moving token, at least the textual identifiers
- // will be visible.
+ // To ensure text associated with moving tokens is visible we add it to the delayed render
+ // list last so it is painted on top of other features.
timer.start("token name/labels");
- renderRenderables(g2d);
+ renderDelayedPaintRenderables(g2d);
timer.stop("token name/labels");
}
@@ -1045,10 +1038,12 @@ public void renderZone(Graphics2D g2d, @Nullable PlayerView view) {
}
private void delayRendering(ItemRenderer renderer) {
- itemRenderList.add(renderer);
+ if (!itemRenderList.contains(renderer)) {
+ itemRenderList.add(renderer);
+ }
}
- private void renderRenderables(Graphics2D g) {
+ private void renderDelayedPaintRenderables(Graphics2D g) {
for (ItemRenderer renderer : itemRenderList) {
renderer.render(g);
}
@@ -1062,7 +1057,7 @@ private void renderRenderables(Graphics2D g) {
*/
private final BufferedImagePool tempBufferPool = new BufferedImagePool(2);
- private void renderLabels(Graphics2D g, PlayerView view) {
+ private void renderMapLabels(Graphics2D g, PlayerView view) {
final var timer = CodeTimer.get();
timer.start("labels-1");
@@ -1079,7 +1074,7 @@ private void renderLabels(Graphics2D g, PlayerView view) {
var dim = fLabel.getDimensions(g, label.getLabel());
Rectangle bounds =
fLabel.render(
- g, (int) (sp.x - dim.width / 2), (int) (sp.y - dim.height / 2), label.getLabel());
+ g, (int) (sp.x - dim.width / 2d), (int) (sp.y - dim.height / 2d), label.getLabel());
labelLocationList.add(new LabelLocation(bounds, label));
timer.stop("labels-1.1");
}
@@ -1261,7 +1256,7 @@ protected void showBlockedMoves(Graphics2D g, PlayerView view, Set
newArea.transform(AffineTransform.getTranslateInstance(set.getOffsetX(), set.getOffsetY()));
var newPosition = new ZoneViewModel.TokenPosition(token, newBounds, newArea);
- tokenRenderer.renderToken(token, newPosition, g, 1);
+ tokenRenderer.renderToken(token, viewModel, newPosition, g, true, true);
// Other details.
// Only draw these if the token is visible on screen where it is dragged to.
@@ -1525,8 +1520,8 @@ public void renderPath(
}
p =
new ZonePoint(
- (int) (p.x + (footprintBounds.width / 2) * footprint.getScale()),
- (int) (p.y + (footprintBounds.height / 2) * footprint.getScale()));
+ (int) (p.x + (footprintBounds.width / 2d) * footprint.getScale()),
+ (int) (p.y + (footprintBounds.height / 2d) * footprint.getScale()));
highlightCell(g, p, RessourceManager.getImage(Images.ZONE_RENDERER_CELL_WAYPOINT), .333f);
}
timer.stop("renderPath-3");
@@ -1725,7 +1720,6 @@ protected void renderTokens(
final var timer = CodeTimer.get();
Graphics2D clippedG = g;
- var imageLabelFactory = new FlatImageLabelFactory();
boolean isGMView = view.isGMView(); // speed things up
@@ -1758,12 +1752,10 @@ protected void renderTokens(
position = viewModel.getTokenPositions().get(token.getId());
if (position == null) {
- // Unknown token?
- continue;
+ continue; // Unknown token?
}
if (!viewModel.getVisibleTokens(token.getLayer()).contains(token.getId())) {
- // Token not on screen or otherwise not visible.
- continue;
+ continue; // Token not on screen or otherwise not visible.
}
} finally {
timer.stop("token-list-1");
@@ -1780,8 +1772,8 @@ protected void renderTokens(
}
} else {
tokenG = (Graphics2D) g.create();
- AppPreferences.renderQuality.get().setRenderingHints(tokenG);
}
+ AppPreferences.renderQuality.get().setRenderingHints(tokenG);
// Previous path
timer.start("renderTokens:ShowPath");
@@ -1790,118 +1782,13 @@ protected void renderTokens(
}
timer.stop("renderTokens:ShowPath");
- timer.start("token-list-1b");
- // get token image, using image table if present
- BufferedImage image = ImageSupport.getTokenImage(token, this);
- timer.stop("token-list-1b");
-
- timer.start("token-list-5a");
- if (token.getIsFlippedIso() && getZone().getGrid().isIsometric()) {
- int newSize = (image.getWidth() + image.getHeight());
- token.setWidth(newSize);
- token.setHeight(newSize / 2);
- }
- timer.stop("token-list-5a");
-
- // Render Halo
- haloRenderer.renderHalo(tokenG, token, position);
-
- // Calculate alpha Transparency from token and use opacity to indicate that token is moving
- float opacity = token.getTokenOpacity();
- if (viewModel.isTokenMoving(token.getId())) {
- opacity = opacity / 2.0f;
- }
- // Finally render the token image
- timer.start("token-list-7");
- // Clipping is handled in the isTokenInNeedOfClipping() call far above.
- tokenRenderer.renderToken(token, position, tokenG, opacity);
- timer.stop("token-list-7");
-
- timer.start("token-list-8");
- // Facing
- facingArrowRenderer.paintArrow(tokenG, position);
- timer.stop("token-list-8");
-
- timer.start("token-list-9");
- // Set up the graphics so that the overlay can just be painted.
- Rectangle2D tokenBounds = zoneScale.toScreenSpace(position.transformedBounds().getBounds2D());
- Graphics2D locG =
- (Graphics2D)
- tokenG.create(
- (int) tokenBounds.getX(),
- (int) tokenBounds.getY(),
- (int) tokenBounds.getWidth(),
- (int) tokenBounds.getHeight());
- Rectangle bounds =
- new Rectangle(0, 0, (int) tokenBounds.getWidth(), (int) tokenBounds.getHeight());
-
- // Check each of the set values
- for (String state : MapTool.getCampaign().getTokenStatesMap().keySet()) {
- Object stateValue = token.getState(state);
- AbstractTokenOverlay overlay = MapTool.getCampaign().getTokenStatesMap().get(state);
- if (stateValue instanceof AbstractTokenOverlay) {
- overlay = (AbstractTokenOverlay) stateValue;
- }
- if (overlay == null
- || overlay.isMouseover() && token != tokenUnderMouse
- || !overlay.showPlayer(token, MapTool.getPlayer())) {
- continue;
- }
- overlay.paintOverlay(locG, token, bounds, stateValue);
- }
- timer.stop("token-list-9");
-
- timer.start("token-list-10");
-
- for (String bar : MapTool.getCampaign().getTokenBarsMap().keySet()) {
- Object barValue = token.getState(bar);
- BarTokenOverlay overlay = MapTool.getCampaign().getTokenBarsMap().get(bar);
- if (overlay == null
- || overlay.isMouseover() && token != tokenUnderMouse
- || !overlay.showPlayer(token, MapTool.getPlayer())) {
- continue;
- }
-
- overlay.paintOverlay(locG, token, bounds, barValue);
- }
- locG.dispose();
- timer.stop("token-list-10");
-
- timer.start("token-list-11");
- // Keep track of which tokens have been drawn for post-processing on them later
- // (such as selection borders and names/labels)
- if (getActiveLayer().equals(token.getLayer())) {
- tokenPostProcessing.add(position);
- }
- timer.stop("token-list-11");
- }
-
- // Selection and labels
- timer.start("token-list-12");
- for (ZoneViewModel.TokenPosition position : tokenPostProcessing) {
- var token = position.token();
-
- // Count moving tokens as "selected" so that a border is drawn around them.
- boolean isSelected =
- selectionModel.isSelected(token.getId()) || viewModel.isTokenMoving(token.getId());
- if (isSelected) {
- selectionRenderer.drawSelectBorder(clippedG, position);
- // Remove labels from the cache if the corresponding tokens are deselected
- } else if (!AppState.isShowTokenNames()) {
- labelRenderingCache.remove(token.getId());
- }
-
- // Token names and labels
- boolean showCurrentTokenLabel = AppState.isShowTokenNames() || token == tokenUnderMouse;
-
- // if policy does not auto-reveal FoW, check if fog covers the token (slow)
- if (showCurrentTokenLabel
- && !isGMView
- && (!zoneView.isUsingVision() || !MapTool.getServerPolicy().isAutoRevealOnMovement())
- && !zone.isTokenVisible(token)) {
- showCurrentTokenLabel = false;
- }
+ timer.start("renderTokens:LabelCheck");
+ // Token name and label
+ boolean showCurrentTokenLabel =
+ LabelRenderer.isLabelVisible(position, viewModel, token == tokenUnderMouse);
+ timer.stop("renderTokens:LabelCheck");
if (showCurrentTokenLabel) {
+ timer.start("renderTokens:LabelBuild");
GUID tokId = token.getId();
int offset = 3; // Keep it from tramping on the token border.
ImageLabel background;
@@ -1923,10 +1810,10 @@ protected void renderTokens(
if (isGMView && token.getGMName() != null && !StringUtil.isEmpty(token.getGMName())) {
name += " (" + token.getGMName() + ")";
}
- if (!view.equals(lastView) || !labelRenderingCache.containsKey(tokId)) {
+ if (!view.equals(lastView) || !LabelRenderer.getLabelImageCache().containsKey(tokId)) {
boolean hasLabel = false;
- var flatImgLabel = imageLabelFactory.getMapImageLabel(token);
+ var flatImgLabel = IMAGE_LABEL_FACTORY.getMapImageLabel(token);
var nameDimension = flatImgLabel.getDimensions(g, name);
var labelDimension = new Dimension(0, 0);
@@ -1950,23 +1837,60 @@ protected void renderTokens(
token.getLabel());
}
flatImgLabel.render(gLabelRender, (width - nameDimension.width) / 2, 0, name);
-
// Add image to cache
- labelRenderingCache.put(tokId, labelRender);
+ LabelRenderer.getLabelImageCache().put(tokId, labelRender);
}
// Create LabelRenderer using cached label.
- Rectangle r =
- zoneScale.toScreenSpace(position.transformedBounds().getBounds2D()).getBounds();
- delayRendering(
- new LabelRenderer(
- this,
- name,
- r.x + r.width / 2,
- r.y + r.height + offset,
- SwingUtilities.CENTER,
- background,
- foreground,
- tokId));
+ Rectangle r = zoneScale.toScreenSpace(position.footprintBounds().getBounds2D()).getBounds();
+ LabelRenderer label = LabelRenderer.getLabelCache().get(tokId);
+ if (label != null) {
+ label.setX(r.x + r.width / 2);
+ label.setY(r.y + r.height + offset);
+ } else {
+ label =
+ new LabelRenderer(
+ this,
+ name,
+ r.x + r.width / 2,
+ r.y + r.height + offset,
+ SwingUtilities.CENTER,
+ background,
+ foreground,
+ tokId);
+ }
+ LabelRenderer.getLabelCache().put(tokId, label);
+ delayRendering(label);
+ timer.stop("renderTokens:LabelBuild");
+ } else {
+ LabelRenderer.getLabelCache().remove(token.getId());
+ }
+
+ // Render the token image and decorations
+ timer.start("token-list-7");
+ // Clipping is handled in the isTokenInNeedOfClipping() call far above.
+ boolean isSelected = selectionModel.isSelected(token.getId());
+ boolean isMoving = viewModel.isTokenMoving(token.getId());
+ boolean isHover = token == tokenUnderMouse;
+ tokenRenderer.renderToken(
+ token, viewModel, position, tokenG, decorationRenderer, isSelected, isMoving, isHover);
+ tokenG.dispose();
+ timer.stop("token-list-7");
+
+ timer.start("token-list-11");
+ // Keep track of which tokens have been drawn for post-processing selection border
+ if (getActiveLayer().equals(token.getLayer())) {
+ tokenPostProcessing.add(position);
+ }
+ timer.stop("token-list-11");
+ }
+
+ // Selection
+ timer.start("token-list-12");
+ for (ZoneViewModel.TokenPosition position : tokenPostProcessing) {
+ var token = position.token();
+ // Count moving tokens as "selected" so that a border is drawn around them.
+ if (selectionModel.isSelected(token.getId()) || viewModel.isTokenMoving(token.getId())) {
+ selectionRenderer.drawSelectBorder(clippedG, position);
}
}
timer.stop("token-list-12");
@@ -2462,7 +2386,7 @@ sure the current Player owns the token being duplicated (to avoid subtle ways of
for (MD5Key id : token.getAllImageAssets()) {
Asset asset = AssetManager.getAsset(id);
if (asset == null) {
- log.error("Could not find image for asset: " + id);
+ log.error("Could not find image for asset: {}", id);
continue;
}
MapToolUtil.uploadAsset(asset);
@@ -2536,6 +2460,7 @@ public List getVisibleTokens() {
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {}
+ @SuppressWarnings("unused")
@Subscribe
private void onSelectionChanged(SelectionModel.SelectionChanged event) {
if (event.zone() != zone) {
@@ -2546,6 +2471,7 @@ private void onSelectionChanged(SelectionModel.SelectionChanged event) {
repaintDebouncer.dispatch();
}
+ @SuppressWarnings("unused")
@Subscribe
private void onTokensAdded(TokensAdded event) {
if (event.zone() != this.zone) {
@@ -2559,6 +2485,7 @@ private void onTokensAdded(TokensAdded event) {
repaintDebouncer.dispatch();
}
+ @SuppressWarnings("unused")
@Subscribe
private void onTokensRemoved(TokensRemoved event) {
if (event.zone() != this.zone) {
@@ -2572,6 +2499,7 @@ private void onTokensRemoved(TokensRemoved event) {
repaintDebouncer.dispatch();
}
+ @SuppressWarnings("unused")
@Subscribe
private void onTokensChanged(TokensChanged event) {
if (event.zone() != this.zone) {
@@ -2585,6 +2513,7 @@ private void onTokensChanged(TokensChanged event) {
repaintDebouncer.dispatch();
}
+ @SuppressWarnings("unused")
@Subscribe
private void onFogChanged(FogChanged event) {
if (event.zone() != this.zone) {
@@ -2603,6 +2532,7 @@ private void onTopologyChanged() {
repaintDebouncer.dispatch();
}
+ @SuppressWarnings("unused")
@Subscribe
private void onTopologyChanged(WallTopologyChanged event) {
if (event.zone() != this.zone) {
@@ -2611,6 +2541,7 @@ private void onTopologyChanged(WallTopologyChanged event) {
onTopologyChanged();
}
+ @SuppressWarnings("unused")
@Subscribe
private void onTopologyChanged(MaskTopologyChanged event) {
if (event.zone() != this.zone) {
@@ -2623,6 +2554,7 @@ private void markDrawableLayerDirty(Layer layer) {
drawableRenderers.get(layer).setDirty();
}
+ @SuppressWarnings("unused")
@Subscribe
private void onDrawableAdded(DrawableAdded event) {
if (event.zone() != this.zone) {
@@ -2633,6 +2565,7 @@ private void onDrawableAdded(DrawableAdded event) {
repaintDebouncer.dispatch();
}
+ @SuppressWarnings("unused")
@Subscribe
private void onDrawableRemoved(DrawableRemoved event) {
if (event.zone() != this.zone) {
@@ -2643,6 +2576,7 @@ private void onDrawableRemoved(DrawableRemoved event) {
repaintDebouncer.dispatch();
}
+ @SuppressWarnings("unused")
@Subscribe
private void onBoardChanged(BoardChanged event) {
if (event.zone() != this.zone) {
@@ -2652,6 +2586,7 @@ private void onBoardChanged(BoardChanged event) {
}
// Should this be moved to GridRenderer? No. Lots of things depend on the grid.
+ @SuppressWarnings("unused")
@Subscribe
private void onGridChanged(GridChanged event) {
if (event.zone() != this.zone) {
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/FacingArrowRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/FacingArrowRenderer.java
index 5b0aeef38f..3463e764dc 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/FacingArrowRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/FacingArrowRenderer.java
@@ -14,17 +14,20 @@
*/
package net.rptools.maptool.client.ui.zone.renderer.tokenRender;
+import com.google.common.eventbus.Subscribe;
import java.awt.*;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Path2D;
-import java.awt.geom.Rectangle2D;
+import java.awt.geom.*;
import java.util.ArrayList;
import net.rptools.lib.CodeTimer;
+import net.rptools.lib.GeometryUtil;
import net.rptools.maptool.client.AppPreferences;
import net.rptools.maptool.client.ui.zone.ZoneViewModel.TokenPosition;
import net.rptools.maptool.client.ui.zone.renderer.RenderHelper;
+import net.rptools.maptool.model.GridFactory;
import net.rptools.maptool.model.Token.TokenShape;
import net.rptools.maptool.model.Zone;
+import net.rptools.maptool.model.zones.GridChanged;
+import net.rptools.maptool.util.GraphicsUtil;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
@@ -45,11 +48,24 @@ public class FacingArrowRenderer {
}
private final RenderHelper renderHelper;
- private final Zone zone;
+ private Zone zone;
private final ArrayList figureFillColours = new ArrayList<>();
+
private final Color fillColour = Color.YELLOW;
private final Color borderColour = Color.DARK_GRAY;
+ private boolean isIsometric;
+ private boolean isSquare;
+
+ @SuppressWarnings("unused")
+ @Subscribe
+ private void onGridChanged(GridChanged event) {
+ if (event.zone() != null) {
+ this.zone = event.zone();
+ isIsometric = this.zone.getGrid().isIsometric();
+ isSquare = GridFactory.getGridType(this.zone.getGrid()).equals(GridFactory.SQUARE);
+ }
+ }
public FacingArrowRenderer(RenderHelper renderHelper, Zone zone) {
this.renderHelper = renderHelper;
@@ -60,9 +76,11 @@ public FacingArrowRenderer(RenderHelper renderHelper, Zone zone) {
for (int i = 89; i >= 0; i--) {
figureFillColours.add(figureFillColours.get(i));
}
+ isIsometric = this.zone.getGrid().isIsometric();
+ isSquare = GridFactory.getGridType(this.zone.getGrid()).equals(GridFactory.SQUARE);
}
- public void paintArrow(Graphics2D tokenG, TokenPosition position) {
+ public void paintArrow(Graphics2D g2d, TokenPosition position) {
var timer = CodeTimer.get();
var token = position.token();
var tokenShape = token.getShape();
@@ -83,8 +101,10 @@ public void paintArrow(Graphics2D tokenG, TokenPosition position) {
timer.stop("FacingArrowRenderer-preCheck");
timer.start("FacingArrowRenderer-render");
+ // set the stroke to shrink for tiny tokens to prevent it crowding out the fill
+ g2d.setStroke(new BasicStroke((float) (0.85f * position.token().getSizeScale())));
renderHelper.render(
- tokenG,
+ g2d,
worldG ->
paintArrowWorld(worldG, token.getFacing(), tokenShape, position.footprintBounds()));
timer.stop("FacingArrowRenderer-render");
@@ -95,8 +115,6 @@ private void paintArrowWorld(
var timer = CodeTimer.get();
timer.start("FacingArrowRenderer-paintArrow");
try {
- final var isIsometric = zone.getGrid().isIsometric();
-
timer.start("FacingArrowRenderer-calculateTransform");
int angle = Math.floorMod(facing + (isIsometric ? 45 : 0), 360);
AffineTransform transform =
@@ -107,49 +125,67 @@ private void paintArrowWorld(
Shape facingArrow = transform.createTransformedShape(UNIT_ARROW);
timer.stop("FacingArrowRenderer-transformArrow");
- timer.start("FacingArrowRenderer-fill");
+ // draw first so that fill is always visible
+ tokenG.setColor(borderColour);
+ tokenG.draw(facingArrow);
+
if (TokenShape.FIGURE.equals(tokenShape) && angle <= 180) {
tokenG.setColor(figureFillColours.get(angle));
} else {
tokenG.setColor(fillColour);
}
tokenG.fill(facingArrow);
- timer.stop("FacingArrowRenderer-fill");
-
- timer.start("FacingArrowRenderer-draw");
- tokenG.setColor(borderColour);
- tokenG.draw(facingArrow);
- timer.stop("FacingArrowRenderer-draw");
} catch (Exception e) {
log.error("Failed to paint facing arrow.", e);
- } finally {
- timer.stop("FacingArrowRenderer-paintArrow");
}
+ timer.stop("FacingArrowRenderer-paintArrow");
}
- private static AffineTransform buildArrowTransform(
+ private AffineTransform buildArrowTransform(
TokenShape shape, Rectangle2D footprintBounds, int angle, boolean isIsometric) {
double radFacing = Math.toRadians(angle);
AffineTransform transform = new AffineTransform();
+ // move to footprint centre
transform.translate(footprintBounds.getCenterX(), footprintBounds.getCenterY());
if (isIsometric) {
transform.scale(1.0, 0.5);
}
+ // spin to face correct direction. Not linear for isometric
transform.rotate(-radFacing);
- double distanceToPoint = footprintBounds.getWidth() / 2;
- if (TokenShape.SQUARE.equals(shape) && !isIsometric) {
- if (angle >= 45 && angle <= 135 || angle >= 225 && angle <= 315) { // Top or bottom face.
- distanceToPoint = footprintBounds.getHeight() / 2 / Math.abs(Math.sin(radFacing));
- } else { // Left or right face
- distanceToPoint = footprintBounds.getWidth() / 2 / Math.abs(Math.cos(radFacing));
- }
+ // calculate distance to edge
+ double distanceToPoint;
+ Shape cellShape = this.zone.getGrid().getCellShape();
+ if (cellShape != null) {
+ Point2D centre = new Point2D.Double(0, 0);
+ // centre the cell shape
+ cellShape =
+ AffineTransform.getTranslateInstance(
+ -cellShape.getBounds2D().getCenterX(), -cellShape.getBounds2D().getCenterY())
+ .createTransformedShape(cellShape);
+ double scale = footprintBounds.getWidth() / cellShape.getBounds2D().getWidth();
+ // size the cell shape to the footprint - compensate for previous isometric scaling
+ cellShape =
+ AffineTransform.getScaleInstance(scale, isIsometric ? 2 * scale : scale)
+ .createTransformedShape(cellShape);
+ // create a line from the centre with token facing angle
+ Point2D farPoint = GraphicsUtil.getPointAtVector(centre, angle, 300 * scale);
+ Line2D.Double ray = new Line2D.Double(centre, farPoint);
+ // obtain the point the line intersects the cell shape
+ Point2D[] point2D = GeometryUtil.lineSegmentShapeIntersection(ray, cellShape);
+ distanceToPoint = Math.hypot(point2D[0].getX(), point2D[0].getY());
+ } else {
+ // fallback for gridless, just use radius based on size
+ distanceToPoint = footprintBounds.getWidth() / 2;
}
+ // move out to edge
transform.translate(distanceToPoint, 0);
- var size = footprintBounds.getWidth() / 2d;
- transform.scale(size, size);
+ var sizeW = footprintBounds.getWidth() / 2d;
+ var sizeH = footprintBounds.getHeight() / 2d;
+ // make it look big
+ transform.scale(sizeW, sizeH);
return transform;
}
}
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java
new file mode 100644
index 0000000000..8d713c95ae
--- /dev/null
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java
@@ -0,0 +1,103 @@
+/*
+ * 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.client.ui.zone.renderer.tokenRender;
+
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.util.*;
+import net.rptools.maptool.client.MapTool;
+import net.rptools.maptool.client.ui.token.AbstractTokenOverlay;
+import net.rptools.maptool.client.ui.token.BarTokenOverlay;
+import net.rptools.maptool.client.ui.token.BooleanTokenOverlay;
+import net.rptools.maptool.client.ui.zone.ZoneViewModel;
+import net.rptools.maptool.client.ui.zone.renderer.RenderHelper;
+import net.rptools.maptool.model.Zone;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+
+public class OverlayRenderer {
+ private static final Logger log = LogManager.getLogger(OverlayRenderer.class);
+ private final RenderHelper renderHelper;
+ private final Zone zone;
+ private final Map barMap =
+ Collections.synchronizedMap(MapTool.getCampaign().getTokenBarsMap());
+ private final Map stateMap =
+ Collections.synchronizedMap(MapTool.getCampaign().getTokenStatesMap());
+ private Set overlayNames;
+ private boolean isPaintBars = false;
+
+ public OverlayRenderer(RenderHelper renderHelper, Zone zone) {
+ this.renderHelper = renderHelper;
+ this.zone = zone;
+ }
+
+ public void renderStates(
+ ZoneViewModel viewModel,
+ ZoneViewModel.TokenPosition position,
+ Graphics2D g2d,
+ boolean selected,
+ boolean hover) {
+ isPaintBars = false;
+ synchronized (stateMap) {
+ overlayNames = stateMap.keySet();
+ }
+ renderOverlay(viewModel, position, g2d, selected, hover);
+ }
+
+ public void renderBars(
+ ZoneViewModel viewModel,
+ ZoneViewModel.TokenPosition position,
+ Graphics2D g2d,
+ boolean selected,
+ boolean hover) {
+ isPaintBars = true;
+ synchronized (barMap) {
+ overlayNames = barMap.keySet();
+ }
+ renderOverlay(viewModel, position, g2d, selected, hover);
+ }
+
+ @SuppressWarnings("unused")
+ public void renderOverlay(
+ ZoneViewModel viewModel,
+ ZoneViewModel.TokenPosition position,
+ Graphics2D g2d,
+ boolean selected,
+ boolean hover) {
+ Rectangle2D tokenBounds =
+ viewModel.getZoneScale().toScreenSpace(position.footprintBounds().getBounds2D());
+ Graphics2D overlayG =
+ (Graphics2D)
+ g2d.create(
+ (int) tokenBounds.getX(),
+ (int) tokenBounds.getY(),
+ (int) tokenBounds.getWidth(),
+ (int) tokenBounds.getHeight());
+ Rectangle bounds =
+ new Rectangle(0, 0, (int) tokenBounds.getWidth(), (int) tokenBounds.getHeight());
+
+ // Check each of the set values
+ for (String name : overlayNames) {
+ AbstractTokenOverlay overlay = isPaintBars ? barMap.get(name) : stateMap.get(name);
+ Object value = position.token().getState(name);
+ if (overlay == null
+ || overlay.isMouseover() && hover
+ || !overlay.showPlayer(position.token(), MapTool.getPlayer())) {
+ continue;
+ }
+ overlay.paintOverlay(overlayG, position.token(), bounds, value);
+ }
+ }
+}
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenDecorationRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenDecorationRenderer.java
new file mode 100644
index 0000000000..58cbd5af8d
--- /dev/null
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenDecorationRenderer.java
@@ -0,0 +1,80 @@
+/*
+ * 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.client.ui.zone.renderer.tokenRender;
+
+import java.awt.*;
+import net.rptools.lib.CodeTimer;
+import net.rptools.maptool.client.ui.zone.ZoneViewModel;
+import net.rptools.maptool.client.ui.zone.renderer.HaloRenderer;
+import net.rptools.maptool.client.ui.zone.renderer.RenderHelper;
+import net.rptools.maptool.model.Zone;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+
+public class TokenDecorationRenderer {
+ /* Render order by increasing z-index
+ AURA,
+ HALO,
+ TOKEN,
+ STATE,
+ BAR,
+ FACING,
+ LABEL;
+ */
+ private static final Logger log = LogManager.getLogger(TokenDecorationRenderer.class);
+ private final RenderHelper renderHelper;
+ private final Zone zone;
+ private final FacingArrowRenderer FACING_ARROW_RENDERER;
+ private final HaloRenderer HALO_RENDERER;
+ private final OverlayRenderer OVERLAY_RENDERER;
+
+ public TokenDecorationRenderer(RenderHelper renderHelper, Zone zone) {
+ this.renderHelper = renderHelper;
+ this.zone = zone;
+ FACING_ARROW_RENDERER = new FacingArrowRenderer(renderHelper, zone);
+ HALO_RENDERER = new HaloRenderer(renderHelper, zone);
+ OVERLAY_RENDERER = new OverlayRenderer(renderHelper, zone);
+ }
+
+ public void renderDecorations(
+ boolean under,
+ ZoneViewModel viewModel,
+ ZoneViewModel.TokenPosition position,
+ Graphics2D g2d,
+ boolean selected,
+ boolean moving,
+ boolean hover) {
+ var timer = CodeTimer.get();
+ timer.increment("TokenDecorationRenderer-render");
+ if (under) {
+ timer.start("TokenDecorationRenderer-renderUnder");
+ // paint Halo
+ renderHelper.render(g2d, worldG -> HALO_RENDERER.renderHalo(worldG, position));
+ // paint TOKEN
+ timer.stop("TokenDecorationRenderer-renderUnder");
+ } else {
+ timer.start("TokenDecorationRenderer-renderOver");
+ // paint STATE
+ OVERLAY_RENDERER.renderStates(viewModel, position, g2d, selected, hover);
+ // paint BAR
+ OVERLAY_RENDERER.renderBars(viewModel, position, g2d, selected, hover);
+ // paint FACING
+ FACING_ARROW_RENDERER.paintArrow(g2d, position);
+ // paint LABEL
+ // Not yet implemented;
+ timer.stop("TokenDecorationRenderer-renderOver");
+ }
+ }
+}
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenRenderer.java
index fd5c5237b8..ee5c3791e0 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenRenderer.java
@@ -25,6 +25,7 @@
import net.rptools.lib.CodeTimer;
import net.rptools.lib.MD5Key;
import net.rptools.maptool.client.MapTool;
+import net.rptools.maptool.client.ui.zone.ZoneViewModel;
import net.rptools.maptool.client.ui.zone.ZoneViewModel.TokenPosition;
import net.rptools.maptool.client.ui.zone.renderer.RenderHelper;
import net.rptools.maptool.model.*;
@@ -46,11 +47,39 @@ public TokenRenderer(RenderHelper renderHelper, Zone zone) {
this.zone = zone;
}
- public void renderToken(Token token, TokenPosition position, Graphics2D g2d, float opacity) {
+ public void renderToken(
+ Token token,
+ ZoneViewModel viewModel,
+ TokenPosition position,
+ Graphics2D g2d,
+ boolean isSelected,
+ boolean isMoving) {
+ renderToken(token, viewModel, position, g2d, null, isSelected, isMoving, false);
+ }
+
+ public void renderToken(
+ Token token,
+ ZoneViewModel viewModel,
+ TokenPosition position,
+ Graphics2D g2d,
+ TokenDecorationRenderer decorationRenderer,
+ boolean isSelected,
+ boolean isMoving,
+ boolean isHover) {
var timer = CodeTimer.get();
+ if (decorationRenderer != null) {
+ decorationRenderer.renderDecorations(
+ true, viewModel, position, g2d, isSelected, isMoving, isHover);
+ }
timer.increment("TokenRenderer-renderToken");
timer.start("TokenRenderer-renderToken");
+ // Calculate alpha Transparency from token and use opacity to indicate that token is moving
+ float opacity =
+ viewModel.isTokenMoving(token.getId())
+ ? token.getTokenOpacity() / 2f
+ : isSelected && isHover ? 1 : token.getTokenOpacity();
+
timer.start("TokenRenderer-loadImageTable");
if (token.getHasImageTable() && !imageTableMap.containsKey(token.getImageTableName())) {
(new CacheTableImagesWorker(token.getImageTableName())).execute();
@@ -58,9 +87,14 @@ public void renderToken(Token token, TokenPosition position, Graphics2D g2d, flo
timer.stop("TokenRenderer-loadImageTable");
timer.start("TokenRenderer-paintTokenImage");
- renderHelper.render(
- g2d, worldG -> paintTokenImage(worldG, position, opacity * token.getTokenOpacity()));
+
+ renderHelper.render(g2d, worldG -> paintTokenImage(worldG, position, opacity));
timer.stop("TokenRenderer-paintTokenImage");
+
+ if (decorationRenderer != null) {
+ decorationRenderer.renderDecorations(
+ false, viewModel, position, g2d, isSelected, isMoving, isHover);
+ }
timer.stop("TokenRenderer-renderToken");
}
diff --git a/src/main/java/net/rptools/maptool/util/GraphicsUtil.java b/src/main/java/net/rptools/maptool/util/GraphicsUtil.java
index 5a80cf7e42..7b085ee1ba 100644
--- a/src/main/java/net/rptools/maptool/util/GraphicsUtil.java
+++ b/src/main/java/net/rptools/maptool/util/GraphicsUtil.java
@@ -408,7 +408,7 @@ public static Area createLine(int width, Point2D... points) {
return new Area(path);
}
- private static Point2D getPointAtVector(Point2D point, double angle, double length) {
+ public static Point2D getPointAtVector(Point2D point, double angle, double length) {
double x = point.getX() + length * Math.cos(Math.toRadians(angle));
double y = point.getY() - length * Math.sin(Math.toRadians(angle));
return new Point2D.Double(x, y);
From b47c568ab817759e636d3f99088e9256a5d66ebe Mon Sep 17 00:00:00 2001
From: bubblobill <45483160+bubblobill@users.noreply.github.com>
Date: Sun, 3 Aug 2025 01:15:03 +0800
Subject: [PATCH 2/8] Fix to pass tests
---
.../tokenRender/FacingArrowRenderer.java | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/FacingArrowRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/FacingArrowRenderer.java
index 3463e764dc..050edf177e 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/FacingArrowRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/FacingArrowRenderer.java
@@ -62,8 +62,13 @@ public class FacingArrowRenderer {
private void onGridChanged(GridChanged event) {
if (event.zone() != null) {
this.zone = event.zone();
- isIsometric = this.zone.getGrid().isIsometric();
- isSquare = GridFactory.getGridType(this.zone.getGrid()).equals(GridFactory.SQUARE);
+ if (zone.getGrid() == null) {
+ isIsometric = false;
+ isSquare = false;
+ } else {
+ isIsometric = this.zone.getGrid().isIsometric();
+ isSquare = GridFactory.getGridType(this.zone.getGrid()).equals(GridFactory.SQUARE);
+ }
}
}
@@ -76,8 +81,13 @@ public FacingArrowRenderer(RenderHelper renderHelper, Zone zone) {
for (int i = 89; i >= 0; i--) {
figureFillColours.add(figureFillColours.get(i));
}
- isIsometric = this.zone.getGrid().isIsometric();
- isSquare = GridFactory.getGridType(this.zone.getGrid()).equals(GridFactory.SQUARE);
+ if (zone.getGrid() == null) {
+ isIsometric = false;
+ isSquare = false;
+ } else {
+ isIsometric = this.zone.getGrid().isIsometric();
+ isSquare = GridFactory.getGridType(this.zone.getGrid()).equals(GridFactory.SQUARE);
+ }
}
public void paintArrow(Graphics2D g2d, TokenPosition position) {
From 67d37ec896945ecbae0d62a517a3213b3e9ff5bf Mon Sep 17 00:00:00 2001
From: bubblobill <45483160+bubblobill@users.noreply.github.com>
Date: Sun, 3 Aug 2025 20:23:14 +0800
Subject: [PATCH 3/8] Removed clipping from overlay graphics object
---
.../client/ui/zone/renderer/tokenRender/OverlayRenderer.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java
index 8d713c95ae..0144e9bc86 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java
@@ -85,6 +85,7 @@ public void renderOverlay(
(int) tokenBounds.getY(),
(int) tokenBounds.getWidth(),
(int) tokenBounds.getHeight());
+ overlayG.setClip(null);
Rectangle bounds =
new Rectangle(0, 0, (int) tokenBounds.getWidth(), (int) tokenBounds.getHeight());
@@ -99,5 +100,6 @@ public void renderOverlay(
}
overlay.paintOverlay(overlayG, position.token(), bounds, value);
}
+ overlayG.dispose();
}
}
From 6bff7d66c9ea2236c6318406a85bc7eb2c13de84 Mon Sep 17 00:00:00 2001
From: bubblobill <45483160+bubblobill@users.noreply.github.com>
Date: Fri, 8 Aug 2025 15:35:32 +0800
Subject: [PATCH 4/8] Renamed OverlayRenderer to StateRenderer. Moved state
opacity check to StateRenderer. Moved StateRenderer out of ZR and into
TokenRenderer. Changed rendering for translucent tokens to be opaque on hover
or selected.
---
.../client/ui/token/BooleanTokenOverlay.java | 6 ----
.../client/ui/zone/renderer/ZoneRenderer.java | 15 ++++-----
...verlayRenderer.java => StateRenderer.java} | 19 +++++++-----
.../tokenRender/TokenDecorationRenderer.java | 22 +++++++++----
.../renderer/tokenRender/TokenRenderer.java | 31 ++++++-------------
5 files changed, 43 insertions(+), 50 deletions(-)
rename src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/{OverlayRenderer.java => StateRenderer.java} (88%)
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/BooleanTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/BooleanTokenOverlay.java
index 6bacee5fac..f2258690c2 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/BooleanTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/BooleanTokenOverlay.java
@@ -14,7 +14,6 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import net.rptools.maptool.model.Token;
@@ -52,11 +51,6 @@ protected BooleanTokenOverlay(String aName) {
@Override
public void paintOverlay(Graphics2D g, Token token, Rectangle bounds, Object value) {
if (FunctionUtil.getBooleanValue(value)) {
- // Apply Alpha Transparency
- float opacity = token.getTokenOpacity();
- if (opacity < 1.0f)
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
-
paintOverlay(g, token, bounds);
}
}
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ZoneRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ZoneRenderer.java
index e1db482b72..b8ac29fd70 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ZoneRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/ZoneRenderer.java
@@ -55,7 +55,6 @@
import net.rptools.maptool.client.ui.token.dialog.create.NewTokenDialog;
import net.rptools.maptool.client.ui.zone.*;
import net.rptools.maptool.client.ui.zone.gdx.GdxRenderer;
-import net.rptools.maptool.client.ui.zone.renderer.tokenRender.TokenDecorationRenderer;
import net.rptools.maptool.client.ui.zone.renderer.tokenRender.TokenRenderer;
import net.rptools.maptool.client.walker.ZoneWalker;
import net.rptools.maptool.events.MapToolEventBus;
@@ -133,7 +132,6 @@ public class ZoneRenderer extends JComponent implements DropTargetListener {
private final EnumSet disabledLayers = EnumSet.noneOf(Layer.class);
private final GridRenderer gridRenderer;
private final TokenRenderer tokenRenderer;
- private final TokenDecorationRenderer decorationRenderer;
private final SelectionRenderer selectionRenderer;
private final LightsRenderer lightsRenderer;
private final DarknessRenderer darknessRenderer;
@@ -169,7 +167,6 @@ public ZoneRenderer(Zone zone) {
this.gridRenderer = new GridRenderer(this);
this.tokenRenderer = new TokenRenderer(renderHelper, zone);
- this.decorationRenderer = new TokenDecorationRenderer(renderHelper, zone);
this.selectionRenderer = new SelectionRenderer(renderHelper, viewModel, zoneView);
this.lightsRenderer = new LightsRenderer(renderHelper, zone, zoneView);
this.darknessRenderer = new DarknessRenderer(renderHelper, zoneView);
@@ -1256,7 +1253,7 @@ protected void showBlockedMoves(Graphics2D g, PlayerView view, Set
newArea.transform(AffineTransform.getTranslateInstance(set.getOffsetX(), set.getOffsetY()));
var newPosition = new ZoneViewModel.TokenPosition(token, newBounds, newArea);
- tokenRenderer.renderToken(token, viewModel, newPosition, g, true, true);
+ tokenRenderer.renderToken(token, viewModel, newPosition, g, true, true, false);
// Other details.
// Only draw these if the token is visible on screen where it is dragged to.
@@ -1775,6 +1772,8 @@ protected void renderTokens(
}
AppPreferences.renderQuality.get().setRenderingHints(tokenG);
+ boolean isHover = token == tokenUnderMouse;
+
// Previous path
timer.start("renderTokens:ShowPath");
if (showPathList.contains(token) && token.getLastPath() != null) {
@@ -1784,8 +1783,7 @@ protected void renderTokens(
timer.start("renderTokens:LabelCheck");
// Token name and label
- boolean showCurrentTokenLabel =
- LabelRenderer.isLabelVisible(position, viewModel, token == tokenUnderMouse);
+ boolean showCurrentTokenLabel = LabelRenderer.isLabelVisible(position, viewModel, isHover);
timer.stop("renderTokens:LabelCheck");
if (showCurrentTokenLabel) {
timer.start("renderTokens:LabelBuild");
@@ -1870,9 +1868,8 @@ protected void renderTokens(
// Clipping is handled in the isTokenInNeedOfClipping() call far above.
boolean isSelected = selectionModel.isSelected(token.getId());
boolean isMoving = viewModel.isTokenMoving(token.getId());
- boolean isHover = token == tokenUnderMouse;
- tokenRenderer.renderToken(
- token, viewModel, position, tokenG, decorationRenderer, isSelected, isMoving, isHover);
+
+ tokenRenderer.renderToken(token, viewModel, position, tokenG, isSelected, isMoving, isHover);
tokenG.dispose();
timer.stop("token-list-7");
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
similarity index 88%
rename from src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java
rename to src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
index 0144e9bc86..627cd93d9c 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/OverlayRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
@@ -18,17 +18,15 @@
import java.awt.geom.Rectangle2D;
import java.util.*;
import net.rptools.maptool.client.MapTool;
-import net.rptools.maptool.client.ui.token.AbstractTokenOverlay;
-import net.rptools.maptool.client.ui.token.BarTokenOverlay;
-import net.rptools.maptool.client.ui.token.BooleanTokenOverlay;
+import net.rptools.maptool.client.ui.token.*;
import net.rptools.maptool.client.ui.zone.ZoneViewModel;
import net.rptools.maptool.client.ui.zone.renderer.RenderHelper;
import net.rptools.maptool.model.Zone;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
-public class OverlayRenderer {
- private static final Logger log = LogManager.getLogger(OverlayRenderer.class);
+public class StateRenderer {
+ private static final Logger log = LogManager.getLogger(StateRenderer.class);
private final RenderHelper renderHelper;
private final Zone zone;
private final Map barMap =
@@ -38,7 +36,7 @@ public class OverlayRenderer {
private Set overlayNames;
private boolean isPaintBars = false;
- public OverlayRenderer(RenderHelper renderHelper, Zone zone) {
+ public StateRenderer(RenderHelper renderHelper, Zone zone) {
this.renderHelper = renderHelper;
this.zone = zone;
}
@@ -78,6 +76,8 @@ public void renderOverlay(
boolean hover) {
Rectangle2D tokenBounds =
viewModel.getZoneScale().toScreenSpace(position.footprintBounds().getBounds2D());
+ Rectangle bounds =
+ new Rectangle(0, 0, (int) tokenBounds.getWidth(), (int) tokenBounds.getHeight());
Graphics2D overlayG =
(Graphics2D)
g2d.create(
@@ -86,8 +86,6 @@ public void renderOverlay(
(int) tokenBounds.getWidth(),
(int) tokenBounds.getHeight());
overlayG.setClip(null);
- Rectangle bounds =
- new Rectangle(0, 0, (int) tokenBounds.getWidth(), (int) tokenBounds.getHeight());
// Check each of the set values
for (String name : overlayNames) {
@@ -98,6 +96,11 @@ public void renderOverlay(
|| !overlay.showPlayer(position.token(), MapTool.getPlayer())) {
continue;
}
+ if (overlay instanceof TwoToneBarTokenOverlay tt) {
+ overlay =
+ new TwoToneCircleBarTokenOverlay(
+ tt.getName(), tt.getBarColor(), tt.getBgColor(), tt.getThickness(), tt.getSide());
+ }
overlay.paintOverlay(overlayG, position.token(), bounds, value);
}
overlayG.dispose();
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenDecorationRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenDecorationRenderer.java
index 58cbd5af8d..f1c7a5d798 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenDecorationRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenDecorationRenderer.java
@@ -38,14 +38,14 @@ public class TokenDecorationRenderer {
private final Zone zone;
private final FacingArrowRenderer FACING_ARROW_RENDERER;
private final HaloRenderer HALO_RENDERER;
- private final OverlayRenderer OVERLAY_RENDERER;
+ private final StateRenderer OVERLAY_RENDERER;
public TokenDecorationRenderer(RenderHelper renderHelper, Zone zone) {
this.renderHelper = renderHelper;
this.zone = zone;
FACING_ARROW_RENDERER = new FacingArrowRenderer(renderHelper, zone);
HALO_RENDERER = new HaloRenderer(renderHelper, zone);
- OVERLAY_RENDERER = new OverlayRenderer(renderHelper, zone);
+ OVERLAY_RENDERER = new StateRenderer(renderHelper, zone);
}
public void renderDecorations(
@@ -57,6 +57,13 @@ public void renderDecorations(
boolean moving,
boolean hover) {
var timer = CodeTimer.get();
+ Composite oldComposite = g2d.getComposite();
+ if (hover || selected && !moving) {
+ g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));
+ } else {
+ g2d.setComposite(
+ AlphaComposite.getInstance(AlphaComposite.SRC_OVER, position.token().getTokenOpacity()));
+ }
timer.increment("TokenDecorationRenderer-render");
if (under) {
timer.start("TokenDecorationRenderer-renderUnder");
@@ -66,15 +73,18 @@ public void renderDecorations(
timer.stop("TokenDecorationRenderer-renderUnder");
} else {
timer.start("TokenDecorationRenderer-renderOver");
- // paint STATE
- OVERLAY_RENDERER.renderStates(viewModel, position, g2d, selected, hover);
- // paint BAR
- OVERLAY_RENDERER.renderBars(viewModel, position, g2d, selected, hover);
+ if (!moving) {
+ // paint STATE
+ OVERLAY_RENDERER.renderStates(viewModel, position, g2d, selected, hover);
+ // paint BAR
+ OVERLAY_RENDERER.renderBars(viewModel, position, g2d, selected, hover);
+ }
// paint FACING
FACING_ARROW_RENDERER.paintArrow(g2d, position);
// paint LABEL
// Not yet implemented;
timer.stop("TokenDecorationRenderer-renderOver");
}
+ g2d.setComposite(oldComposite);
}
}
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenRenderer.java
index ee5c3791e0..973b0b5963 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/TokenRenderer.java
@@ -41,10 +41,12 @@ public class TokenRenderer {
private final RenderHelper renderHelper;
private final Zone zone;
+ private final TokenDecorationRenderer decorationRenderer;
public TokenRenderer(RenderHelper renderHelper, Zone zone) {
this.renderHelper = renderHelper;
this.zone = zone;
+ this.decorationRenderer = new TokenDecorationRenderer(renderHelper, zone);
}
public void renderToken(
@@ -53,32 +55,20 @@ public void renderToken(
TokenPosition position,
Graphics2D g2d,
boolean isSelected,
- boolean isMoving) {
- renderToken(token, viewModel, position, g2d, null, isSelected, isMoving, false);
- }
-
- public void renderToken(
- Token token,
- ZoneViewModel viewModel,
- TokenPosition position,
- Graphics2D g2d,
- TokenDecorationRenderer decorationRenderer,
- boolean isSelected,
boolean isMoving,
boolean isHover) {
var timer = CodeTimer.get();
- if (decorationRenderer != null) {
- decorationRenderer.renderDecorations(
- true, viewModel, position, g2d, isSelected, isMoving, isHover);
- }
+ decorationRenderer.renderDecorations(
+ true, viewModel, position, g2d, isSelected, isMoving, isHover);
+
timer.increment("TokenRenderer-renderToken");
timer.start("TokenRenderer-renderToken");
// Calculate alpha Transparency from token and use opacity to indicate that token is moving
float opacity =
viewModel.isTokenMoving(token.getId())
- ? token.getTokenOpacity() / 2f
- : isSelected && isHover ? 1 : token.getTokenOpacity();
+ ? Math.max(0.5f, token.getTokenOpacity() / 2f)
+ : isSelected || isHover ? 1 : token.getTokenOpacity();
timer.start("TokenRenderer-loadImageTable");
if (token.getHasImageTable() && !imageTableMap.containsKey(token.getImageTableName())) {
@@ -91,10 +81,9 @@ public void renderToken(
renderHelper.render(g2d, worldG -> paintTokenImage(worldG, position, opacity));
timer.stop("TokenRenderer-paintTokenImage");
- if (decorationRenderer != null) {
- decorationRenderer.renderDecorations(
- false, viewModel, position, g2d, isSelected, isMoving, isHover);
- }
+ decorationRenderer.renderDecorations(
+ false, viewModel, position, g2d, isSelected, isMoving, isHover);
+
timer.stop("TokenRenderer-renderToken");
}
From 11ca0d0919c466c770d3316b880bb4ae24d00195 Mon Sep 17 00:00:00 2001
From: bubblobill <45483160+bubblobill@users.noreply.github.com>
Date: Fri, 8 Aug 2025 15:39:25 +0800
Subject: [PATCH 5/8] tweak
---
.../client/ui/zone/renderer/tokenRender/StateRenderer.java | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
index 627cd93d9c..73b59f470e 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
@@ -96,11 +96,6 @@ public void renderOverlay(
|| !overlay.showPlayer(position.token(), MapTool.getPlayer())) {
continue;
}
- if (overlay instanceof TwoToneBarTokenOverlay tt) {
- overlay =
- new TwoToneCircleBarTokenOverlay(
- tt.getName(), tt.getBarColor(), tt.getBgColor(), tt.getThickness(), tt.getSide());
- }
overlay.paintOverlay(overlayG, position.token(), bounds, value);
}
overlayG.dispose();
From 6e37e0cec22b87db7a04a8676cfe34062523b793 Mon Sep 17 00:00:00 2001
From: bubblobill <45483160+bubblobill@users.noreply.github.com>
Date: Fri, 8 Aug 2025 16:00:53 +0800
Subject: [PATCH 6/8] moved state opacity calculations from state classes to
StateRenderer.
Opacity is now multiple of state opacity and token opacity
---
.../client/ui/token/ColorDotTokenOverlay.java | 7 -------
.../client/ui/token/CrossTokenOverlay.java | 7 -------
.../client/ui/token/DiamondTokenOverlay.java | 8 +-------
.../client/ui/token/FlowColorDotTokenOverlay.java | 7 -------
.../client/ui/token/ImageTokenOverlay.java | 5 -----
.../maptool/client/ui/token/OTokenOverlay.java | 7 -------
.../client/ui/token/ShadedTokenOverlay.java | 7 -------
.../client/ui/token/TriangleTokenOverlay.java | 7 -------
.../maptool/client/ui/token/XTokenOverlay.java | 8 --------
.../client/ui/token/YieldTokenOverlay.java | 7 -------
.../zone/renderer/tokenRender/StateRenderer.java | 15 +++++++++++++++
11 files changed, 16 insertions(+), 69 deletions(-)
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/ColorDotTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/ColorDotTokenOverlay.java
index 939044a5f1..13e24ed803 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/ColorDotTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/ColorDotTokenOverlay.java
@@ -14,9 +14,7 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
import java.awt.Color;
-import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
@@ -78,7 +76,6 @@ public Object clone() {
public void paintOverlay(Graphics2D g, Token aToken, Rectangle bounds) {
Color tempColor = g.getColor();
Stroke tempStroke = g.getStroke();
- Composite tempComposite = g.getComposite();
try {
g.setColor(getColor());
g.setStroke(getStroke());
@@ -101,14 +98,10 @@ public void paintOverlay(Graphics2D g, Token aToken, Rectangle bounds) {
break;
} // endswitch
Shape s = new Ellipse2D.Double(x, y, size, size);
- if (getOpacity() != 100)
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
g.fill(s);
} finally {
g.setColor(tempColor);
g.setStroke(tempStroke);
- g.setComposite(tempComposite);
}
}
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/CrossTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/CrossTokenOverlay.java
index 6e424262c4..b29ad7c474 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/CrossTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/CrossTokenOverlay.java
@@ -14,9 +14,7 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
import java.awt.Color;
-import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
@@ -74,17 +72,12 @@ public void paintOverlay(Graphics2D g, Token aToken, Rectangle bounds) {
g.setColor(getColor());
Stroke tempStroke = g.getStroke();
g.setStroke(getStroke());
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100)
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
g.draw(
new Line2D.Double(0, (double) bounds.height / 2, bounds.width, (double) bounds.height / 2));
g.draw(
new Line2D.Double((double) bounds.width / 2, 0, (double) bounds.width / 2, bounds.height));
g.setColor(tempColor);
g.setStroke(tempStroke);
- g.setComposite(tempComposite);
}
public static CrossTokenOverlay fromDto(BooleanTokenOverlayDto dto) {
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/DiamondTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/DiamondTokenOverlay.java
index 6faf5a9dd8..aef6f46e32 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/DiamondTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/DiamondTokenOverlay.java
@@ -14,9 +14,7 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
import java.awt.Color;
-import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
@@ -76,17 +74,13 @@ public void paintOverlay(Graphics2D g, Token aToken, Rectangle bounds) {
g.setColor(getColor());
Stroke tempStroke = g.getStroke();
g.setStroke(getStroke());
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100)
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
+
g.draw(new Line2D.Double(0, vc, hc, 0));
g.draw(new Line2D.Double(hc, 0, bounds.width, vc));
g.draw(new Line2D.Double(bounds.width, vc, hc, bounds.height));
g.draw(new Line2D.Double(hc, bounds.height, 0, vc));
g.setColor(tempColor);
g.setStroke(tempStroke);
- g.setComposite(tempComposite);
}
public static DiamondTokenOverlay fromDto(BooleanTokenOverlayDto dto) {
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/FlowColorDotTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/FlowColorDotTokenOverlay.java
index c4558d5255..1326e82970 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/FlowColorDotTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/FlowColorDotTokenOverlay.java
@@ -14,9 +14,7 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
import java.awt.Color;
-import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
@@ -91,19 +89,14 @@ protected TokenOverlayFlow getFlow() {
public void paintOverlay(Graphics2D g, Token aToken, Rectangle bounds) {
Color tempColor = g.getColor();
Stroke tempStroke = g.getStroke();
- Composite tempComposite = g.getComposite();
try {
g.setColor(getColor());
g.setStroke(getStroke());
- if (getOpacity() != 100)
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
Shape s = getShape(bounds, aToken);
g.fill(s);
} finally {
g.setColor(tempColor);
g.setStroke(tempStroke);
- g.setComposite(tempComposite);
}
}
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/ImageTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/ImageTokenOverlay.java
index 55e6fa546b..d18d7d82ee 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/ImageTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/ImageTokenOverlay.java
@@ -89,12 +89,7 @@ public void paintOverlay(Graphics2D g, Token token, Rectangle bounds) {
int height = size.height;
int x = iBounds.x + (d.width - width) / 2;
int y = iBounds.y + (d.height - height) / 2;
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100)
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
g.drawImage(image, x, y, size.width, size.height, null);
- g.setComposite(tempComposite);
}
/**
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/OTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/OTokenOverlay.java
index 00fc54da28..e720f76ded 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/OTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/OTokenOverlay.java
@@ -14,9 +14,7 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
import java.awt.Color;
-import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
@@ -73,17 +71,12 @@ public void paintOverlay(Graphics2D g, Token aToken, Rectangle bounds) {
g.setColor(getColor());
Stroke tempStroke = g.getStroke();
g.setStroke(getStroke());
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100)
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
double offset = getStroke().getLineWidth() / 2.0;
g.draw(
new Ellipse2D.Double(
0 + offset, 0 + offset, bounds.width - offset * 2, bounds.height - offset * 2));
g.setColor(tempColor);
g.setStroke(tempStroke);
- g.setComposite(tempComposite);
}
public static OTokenOverlay fromDto(BooleanTokenOverlayDto dto) {
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/ShadedTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/ShadedTokenOverlay.java
index ed904e503d..b392ef8e29 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/ShadedTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/ShadedTokenOverlay.java
@@ -14,9 +14,7 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
import java.awt.Color;
-import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import net.rptools.maptool.model.Token;
@@ -71,13 +69,8 @@ public ShadedTokenOverlay(String aName, Color aColor) {
public void paintOverlay(Graphics2D g, Token aToken, Rectangle bounds) {
Color temp = g.getColor();
g.setColor(color);
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100)
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
g.fill(bounds);
g.setColor(temp);
- g.setComposite(tempComposite);
}
/**
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/TriangleTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/TriangleTokenOverlay.java
index cf89173ecc..a470fa61a3 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/TriangleTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/TriangleTokenOverlay.java
@@ -14,9 +14,7 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
import java.awt.Color;
-import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
@@ -76,16 +74,11 @@ public void paintOverlay(Graphics2D g, Token aToken, Rectangle bounds) {
g.setColor(getColor());
Stroke tempStroke = g.getStroke();
g.setStroke(getStroke());
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100)
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
g.draw(new Line2D.Double(0, vc, bounds.width, vc));
g.draw(new Line2D.Double(bounds.width, vc, hc, 0));
g.draw(new Line2D.Double(hc, 0, 0, vc));
g.setColor(tempColor);
g.setStroke(tempStroke);
- g.setComposite(tempComposite);
}
public static TriangleTokenOverlay fromDto(BooleanTokenOverlayDto dto) {
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/XTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/XTokenOverlay.java
index dd490186db..b40faccfd9 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/XTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/XTokenOverlay.java
@@ -14,10 +14,8 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
-import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
@@ -73,16 +71,10 @@ public void paintOverlay(Graphics2D g, Token aToken, Rectangle bounds) {
g.setColor(color);
Stroke tempStroke = g.getStroke();
g.setStroke(stroke);
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100) {
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
- }
g.draw(new Line2D.Double(0, 0, bounds.width, bounds.height));
g.draw(new Line2D.Double(0, bounds.height, bounds.width, 0));
g.setColor(tempColor);
g.setStroke(tempStroke);
- g.setComposite(tempComposite);
}
/**
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/YieldTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/YieldTokenOverlay.java
index f810f6e5a8..1cf61113bc 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/YieldTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/YieldTokenOverlay.java
@@ -14,9 +14,7 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
import java.awt.Color;
-import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
@@ -76,16 +74,11 @@ public void paintOverlay(Graphics2D g, Token aToken, Rectangle bounds) {
g.setColor(getColor());
Stroke tempStroke = g.getStroke();
g.setStroke(getStroke());
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100)
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
g.draw(new Line2D.Double(0, vc, bounds.width, vc));
g.draw(new Line2D.Double(bounds.width, vc, hc, bounds.height));
g.draw(new Line2D.Double(hc, bounds.height, 0, vc));
g.setColor(tempColor);
g.setStroke(tempStroke);
- g.setComposite(tempComposite);
}
public static YieldTokenOverlay fromDto(BooleanTokenOverlayDto dto) {
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
index 73b59f470e..16680393cb 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
@@ -87,6 +87,12 @@ public void renderOverlay(
(int) tokenBounds.getHeight());
overlayG.setClip(null);
+ Composite oldComposite = g2d.getComposite();
+ float alpha = 1f;
+ if (oldComposite instanceof AlphaComposite alphaComposite) {
+ alpha = alphaComposite.getAlpha();
+ }
+
// Check each of the set values
for (String name : overlayNames) {
AbstractTokenOverlay overlay = isPaintBars ? barMap.get(name) : stateMap.get(name);
@@ -96,6 +102,15 @@ public void renderOverlay(
|| !overlay.showPlayer(position.token(), MapTool.getPlayer())) {
continue;
}
+ overlayG.setComposite(
+ AlphaComposite.getInstance(
+ AlphaComposite.SRC_OVER, alpha * (float) overlay.getOpacity() / 100));
+
+ if (overlay instanceof TwoToneBarTokenOverlay tt) {
+ overlay =
+ new CircleBarTokenOverlay(
+ tt.getName(), tt.getBarColor(), tt.getBgColor(), tt.getThickness(), tt.getSide());
+ }
overlay.paintOverlay(overlayG, position.token(), bounds, value);
}
overlayG.dispose();
From 983bd597edbee0342aa5708c7a89fd8a8eee8e8f Mon Sep 17 00:00:00 2001
From: bubblobill <45483160+bubblobill@users.noreply.github.com>
Date: Fri, 8 Aug 2025 16:07:07 +0800
Subject: [PATCH 7/8] moved bar opacity calculations from bar classes to
StateRenderer.
---
.../client/ui/token/MultipleImageBarTokenOverlay.java | 8 --------
.../client/ui/token/SingleImageBarTokenOverlay.java | 8 --------
.../maptool/client/ui/token/TwoImageBarTokenOverlay.java | 8 --------
3 files changed, 24 deletions(-)
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/MultipleImageBarTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/MultipleImageBarTokenOverlay.java
index cde12ee7b2..872638f636 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/MultipleImageBarTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/MultipleImageBarTokenOverlay.java
@@ -14,8 +14,6 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
-import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
@@ -98,13 +96,7 @@ public void paintOverlay(Graphics2D g, Token token, Rectangle bounds, double val
y = d.height - size.height;
}
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100) {
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
- }
g.drawImage(image, x, y, size.width, size.height, null);
- g.setComposite(tempComposite);
}
/**
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/SingleImageBarTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/SingleImageBarTokenOverlay.java
index 3b621ac125..ed33976d82 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/SingleImageBarTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/SingleImageBarTokenOverlay.java
@@ -14,8 +14,6 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
-import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
@@ -95,11 +93,6 @@ public void paintOverlay(Graphics2D g, Token token, Rectangle bounds, double val
y = d.height - size.height;
}
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100) {
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
- }
int width =
(getSide() == Side.TOP || getSide() == Side.BOTTOM)
? calcBarSize(image.getWidth(), value)
@@ -129,7 +122,6 @@ public void paintOverlay(Graphics2D g, Token token, Rectangle bounds, double val
image.getWidth(),
image.getHeight(),
null);
- g.setComposite(tempComposite);
}
/**
diff --git a/src/main/java/net/rptools/maptool/client/ui/token/TwoImageBarTokenOverlay.java b/src/main/java/net/rptools/maptool/client/ui/token/TwoImageBarTokenOverlay.java
index 0a51d722e7..998bc15459 100644
--- a/src/main/java/net/rptools/maptool/client/ui/token/TwoImageBarTokenOverlay.java
+++ b/src/main/java/net/rptools/maptool/client/ui/token/TwoImageBarTokenOverlay.java
@@ -14,8 +14,6 @@
*/
package net.rptools.maptool.client.ui.token;
-import java.awt.AlphaComposite;
-import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
@@ -102,11 +100,6 @@ public void paintOverlay(Graphics2D g, Token token, Rectangle bounds, double val
y = d.height - size.height;
}
- Composite tempComposite = g.getComposite();
- if (getOpacity() != 100)
- g.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) getOpacity() / 100));
-
int width =
(getSide() == Side.TOP || getSide() == Side.BOTTOM)
? calcBarSize(images[0].getWidth(), value)
@@ -141,7 +134,6 @@ public void paintOverlay(Graphics2D g, Token token, Rectangle bounds, double val
} else {
g.drawImage(images[0], x, y, x + screenWidth, y + screenHeight, 0, 0, width, height, null);
}
- g.setComposite(tempComposite);
}
/**
From a02b0436c3eaf5d14ecd76d1e6ee2ce1f4b876fc Mon Sep 17 00:00:00 2001
From: bubblobill <45483160+bubblobill@users.noreply.github.com>
Date: Fri, 8 Aug 2025 16:09:07 +0800
Subject: [PATCH 8/8] sigh
---
.../client/ui/zone/renderer/tokenRender/StateRenderer.java | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
index 16680393cb..ee883efb67 100644
--- a/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
+++ b/src/main/java/net/rptools/maptool/client/ui/zone/renderer/tokenRender/StateRenderer.java
@@ -106,11 +106,6 @@ public void renderOverlay(
AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha * (float) overlay.getOpacity() / 100));
- if (overlay instanceof TwoToneBarTokenOverlay tt) {
- overlay =
- new CircleBarTokenOverlay(
- tt.getName(), tt.getBarColor(), tt.getBgColor(), tt.getThickness(), tt.getSide());
- }
overlay.paintOverlay(overlayG, position.token(), bounds, value);
}
overlayG.dispose();