diff --git a/runelite-api/src/main/java/net/runelite/api/MainBufferProvider.java b/runelite-api/src/main/java/net/runelite/api/MainBufferProvider.java index 33b3fea3f0..8d57b8efdc 100644 --- a/runelite-api/src/main/java/net/runelite/api/MainBufferProvider.java +++ b/runelite-api/src/main/java/net/runelite/api/MainBufferProvider.java @@ -29,7 +29,7 @@ import java.awt.Image; /** * Represents the clients primary image buffer. */ -public interface MainBufferProvider +public interface MainBufferProvider extends BufferProvider { /** * Gets the image currently loaded in the buffer. diff --git a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java index 12de2c567b..96f4a90bbe 100644 --- a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java +++ b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java @@ -130,6 +130,31 @@ public class Hooks implements Callbacks private long lastCheck; private boolean shouldProcessGameTick; + private static MainBufferProvider lastMainBufferProvider; + private static Graphics2D lastGraphics; + + /** + * Get the Graphics2D for the MainBufferProvider image + * This caches the Graphics2D instance so it can be reused + * @param mainBufferProvider + * @return + */ + private static Graphics2D getGraphics(MainBufferProvider mainBufferProvider) + { + if (lastGraphics == null || lastMainBufferProvider != mainBufferProvider) + { + if (lastGraphics != null) + { + log.debug("Graphics reset!"); + lastGraphics.dispose(); + } + + lastMainBufferProvider = mainBufferProvider; + lastGraphics = (Graphics2D) mainBufferProvider.getImage().getGraphics(); + } + return lastGraphics; + } + @Override public void post(Object event) { @@ -295,9 +320,7 @@ public class Hooks implements Callbacks return; } - Image image = mainBufferProvider.getImage(); - final Image finalImage; - final Graphics2D graphics2d = (Graphics2D) image.getGraphics(); + final Graphics2D graphics2d = getGraphics(mainBufferProvider); try { @@ -313,8 +336,6 @@ public class Hooks implements Callbacks // Draw clientUI overlays clientUi.paintOverlays(graphics2d); - graphics2d.dispose(); - if (client.isGpu()) { // processDrawComplete gets called on GPU by the gpu plugin at the end of its @@ -323,6 +344,8 @@ public class Hooks implements Callbacks } // Stretch the game image if the user has that enabled + Image image = mainBufferProvider.getImage(); + final Image finalImage; if (client.isStretchedEnabled()) { GraphicsConfiguration gc = clientUi.getGraphicsConfiguration(); @@ -392,8 +415,7 @@ public class Hooks implements Callbacks public void drawScene() { MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider(); - BufferedImage image = (BufferedImage) bufferProvider.getImage(); - Graphics2D graphics2d = image.createGraphics(); + Graphics2D graphics2d = getGraphics(bufferProvider); try { @@ -403,18 +425,13 @@ public class Hooks implements Callbacks { log.warn("Error during overlay rendering", ex); } - finally - { - graphics2d.dispose(); - } } @Override public void drawAboveOverheads() { MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider(); - BufferedImage image = (BufferedImage) bufferProvider.getImage(); - Graphics2D graphics2d = image.createGraphics(); + Graphics2D graphics2d = getGraphics(bufferProvider); try { @@ -424,17 +441,12 @@ public class Hooks implements Callbacks { log.warn("Error during overlay rendering", ex); } - finally - { - graphics2d.dispose(); - } } public static void drawAfterWidgets() { MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider(); - BufferedImage image = (BufferedImage) bufferProvider.getImage(); - Graphics2D graphics2d = image.createGraphics(); + Graphics2D graphics2d = getGraphics(bufferProvider); try { @@ -445,10 +457,6 @@ public class Hooks implements Callbacks { log.warn("Error during overlay rendering", ex); } - finally - { - graphics2d.dispose(); - } // WidgetItemOverlays render at ABOVE_WIDGETS, reset widget item // list for next frame. diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java index 9e5820470a..a3dcd552f1 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java @@ -33,6 +33,7 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; +import java.awt.geom.AffineTransform; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; @@ -433,38 +434,45 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener private void safeRender(Client client, Overlay overlay, OverlayLayer layer, Graphics2D graphics, Point point) { - final Graphics2D subGraphics = (Graphics2D) graphics.create(); - if (!isResizeable && (layer == OverlayLayer.ABOVE_SCENE || layer == OverlayLayer.UNDER_WIDGETS)) { - subGraphics.setClip(client.getViewportXOffset(), + graphics.setClip(client.getViewportXOffset(), client.getViewportYOffset(), client.getViewportWidth(), client.getViewportHeight()); } + else + { + graphics.setClip(0, 0, client.getCanvasWidth(), client.getCanvasHeight()); + } final OverlayPosition position = overlay.getPosition(); // Set font based on configuration if (position == OverlayPosition.DYNAMIC || position == OverlayPosition.DETACHED) { - subGraphics.setFont(runeLiteConfig.fontType().getFont()); + graphics.setFont(runeLiteConfig.fontType().getFont()); } else if (position == OverlayPosition.TOOLTIP) { - subGraphics.setFont(runeLiteConfig.tooltipFontType().getFont()); + graphics.setFont(runeLiteConfig.tooltipFontType().getFont()); } else { - subGraphics.setFont(runeLiteConfig.interfaceFontType().getFont()); + graphics.setFont(runeLiteConfig.interfaceFontType().getFont()); } - subGraphics.translate(point.x, point.y); + // Reset the default color + graphics.setColor(Color.WHITE); + + // Get transform so we can reset it after drawing + AffineTransform transform = graphics.getTransform(); + graphics.translate(point.x, point.y); final Dimension overlayDimension; try { - overlayDimension = overlay.render(subGraphics); + overlayDimension = overlay.render(graphics); } catch (Exception ex) { @@ -473,7 +481,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener } finally { - subGraphics.dispose(); + graphics.setTransform(transform); } final Dimension dimension = MoreObjects.firstNonNull(overlayDimension, new Dimension());