From 59c81f86c3aaf9e5e5952f9f8a3c495688598fee Mon Sep 17 00:00:00 2001 From: extio-de Date: Sat, 10 Jan 2026 18:29:07 +0100 Subject: [PATCH] refactor(renderer): optimize icon loading and caching in CustomAbstractButton --- .../components/CustomAbstractButton.java | 65 +++++++++++++------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/control/components/CustomAbstractButton.java b/src/main/java/de/extio/game_engine/renderer/g2d/control/components/CustomAbstractButton.java index 923c014..865b15b 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/control/components/CustomAbstractButton.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/control/components/CustomAbstractButton.java @@ -10,6 +10,8 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; import javax.imageio.ImageIO; @@ -21,6 +23,20 @@ import de.extio.game_engine.spatial2.model.ImmutableCoordI2; @SuppressWarnings("serial") public abstract class CustomAbstractButton extends Component { + private static final int MAX_ICON_CACHE_SIZE = 10; + + private final Map iconCache = new LinkedHashMap<>(MAX_ICON_CACHE_SIZE, 0.75f, true) { + + @Override + protected boolean removeEldestEntry(final Map.Entry eldest) { + final boolean shouldRemove = this.size() > MAX_ICON_CACHE_SIZE; + if (shouldRemove && eldest.getValue() != null) { + eldest.getValue().flush(); + } + return shouldRemove; + } + }; + protected static final int STATE_NORMAL = 0; protected static final int STATE_TOGGLED = 1; @@ -183,38 +199,45 @@ public abstract class CustomAbstractButton extends Component { } public void close() { - this.flushIcon(); + this.icon = null; + for (final var cachedIcon : this.iconCache.values()) { + if (cachedIcon != null) { + cachedIcon.flush(); + } + } + this.iconCache.clear(); } @SuppressWarnings("resource") protected void loadIcon() { if (this.iconResource != null && this.staticResourceService != null) { this.loadedIconResource = this.iconResource; - this.flushIcon(); + this.icon = null; - final var in = this.staticResourceService.loadStreamByPath(this.iconResource); - if (in.isPresent()) { - try (var stream = in.get()) { - if (stream != null) { - this.icon = ImageIO.read(stream); - } - } - catch (final IOException e) { - throw new RuntimeException(e); - } - } + final String iconKey = this.iconResource.toString(); + + this.icon = this.iconCache.get(iconKey); if (this.icon == null) { - throw new RuntimeException("Resource not found: " + this.iconResource); + final var in = this.staticResourceService.loadStreamByPath(this.iconResource); + if (in.isPresent()) { + try (var stream = in.get()) { + if (stream != null) { + this.icon = ImageIO.read(stream); + } + } + catch (final IOException e) { + throw new RuntimeException(e); + } + } + + if (this.icon == null) { + throw new RuntimeException("Resource not found: " + this.iconResource); + } + + this.iconCache.put(iconKey, this.icon); } } } - protected void flushIcon() { - if (this.icon != null) { - this.icon.flush(); - this.icon = null; - } - } - }