From 9dcd9d8a7d3bc16eb6fde3681cd32e02dc0707e9 Mon Sep 17 00:00:00 2001 From: Svjatoslav Agejenko Date: Mon, 23 Jul 2018 01:12:39 +0300 Subject: [PATCH] Optimized frame repainting. Fixed mouse click processing. --- .../sixth/e3d/gui/GuiComponent.java | 10 +-- .../sixth/e3d/gui/RenderingContext.java | 13 +--- .../svjatoslav/sixth/e3d/gui/ViewPanel.java | 62 ++++++++++--------- .../e3d/gui/humaninput/HIDInputTracker.java | 61 +++++++++--------- .../gui/humaninput/KeyboardFocusStack.java | 12 ++-- .../{MouseClick.java => MouseEvent.java} | 6 +- .../MouseInteractionController.java | 9 ++- .../basic/solidpolygon/SolidPolygon.java | 6 +- .../texturedpolygon/TexturedPolygon.java | 11 ++-- 9 files changed, 99 insertions(+), 91 deletions(-) rename src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/{MouseClick.java => MouseEvent.java} (82%) diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/GuiComponent.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/GuiComponent.java index 70350e0..62e8eaf 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/GuiComponent.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/GuiComponent.java @@ -105,16 +105,18 @@ public class GuiComponent extends AbstractCompositeShape implements } @Override - public void mouseClicked() { - viewPanel.getKeyboardFocusStack().pushFocusOwner(this); + public boolean mouseClicked() { + return viewPanel.getKeyboardFocusStack().pushFocusOwner(this); } @Override - public void mouseEntered() { + public boolean mouseEntered() { + return false; } @Override - public void mouseExited() { + public boolean mouseExited() { + return false; } private void setDimensions(final Point3D size) { diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/RenderingContext.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/RenderingContext.java index afbe22d..2603c11 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/RenderingContext.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/RenderingContext.java @@ -9,7 +9,7 @@ package eu.svjatoslav.sixth.e3d.gui; -import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseClick; +import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseEvent; import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseInteractionController; import java.awt.*; @@ -30,22 +30,15 @@ public class RenderingContext { final BufferedImage bufferedImage; public int frameNumber = 0; - /** - * Used to signal that actual rendering should be performed. It is useful to - * skip rendering when we only want to detect mouse clicks intersections - * without actually updating rendered frame. - */ - public boolean doRender = true; // TODO: make use of the variable - /** * Mouse click. During rendering we can detect which item user clicked on. */ - public MouseClick mouseClick; + public MouseEvent mouseEvent; /** * Item that user clicked on. */ - public MouseInteractionController clickedItem; + public MouseInteractionController objectUnderMouse; public RenderingContext(final int width, final int height) { this.width = width; diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewPanel.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewPanel.java index ea55a31..84d4529 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewPanel.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewPanel.java @@ -127,27 +127,23 @@ public class ViewPanel extends JPanel implements ComponentListener { } private void handleDetectedComponentMouseEvents() { - if (renderingContext.clickedItem != null) { - if (renderingContext.mouseClick.button == 0) { + if (renderingContext.objectUnderMouse != null) { + if (renderingContext.mouseEvent.button == 0) { // mouse over if (currentMouseOverComponent == null) { - currentMouseOverComponent = renderingContext.clickedItem; - currentMouseOverComponent.mouseEntered(); - viewRepaintNeeded = true; - } else if (currentMouseOverComponent != renderingContext.clickedItem) { - currentMouseOverComponent.mouseExited(); - currentMouseOverComponent = renderingContext.clickedItem; - currentMouseOverComponent.mouseEntered(); - viewRepaintNeeded = true; + currentMouseOverComponent = renderingContext.objectUnderMouse; + viewRepaintNeeded |= currentMouseOverComponent.mouseEntered(); + } else if (currentMouseOverComponent != renderingContext.objectUnderMouse) { + viewRepaintNeeded |= currentMouseOverComponent.mouseExited(); + currentMouseOverComponent = renderingContext.objectUnderMouse; + viewRepaintNeeded |= currentMouseOverComponent.mouseEntered(); } } else { // mouse click - renderingContext.clickedItem.mouseClicked(); - viewRepaintNeeded = true; + viewRepaintNeeded |= renderingContext.objectUnderMouse.mouseClicked(); } } else if (currentMouseOverComponent != null) { - currentMouseOverComponent.mouseExited(); - viewRepaintNeeded = true; + viewRepaintNeeded |= currentMouseOverComponent.mouseExited(); currentMouseOverComponent = null; } } @@ -162,8 +158,6 @@ public class ViewPanel extends JPanel implements ComponentListener { } private void renderFrame() { - if (isNewRenderingContextNeeded()) - renderingContext = new RenderingContext(getWidth(), getHeight()); // paint root geometry collection to the offscreen render buffer clearCanvas(); @@ -180,12 +174,6 @@ public class ViewPanel extends JPanel implements ComponentListener { renderingContext.graphics.fillRect(0, 0, getWidth(), getHeight()); } - private boolean isNewRenderingContextNeeded() { - return (renderingContext == null) - || (renderingContext.width != getWidth()) - || (renderingContext.height != getHeight()); - } - /** * Calling this methods tells 3D engine that current 3D view needs to be * repainted on first opportunity. @@ -234,10 +222,7 @@ public class ViewPanel extends JPanel implements ComponentListener { * graphics is needed. */ void updateView() { - if (renderingContext != null) { - renderingContext.mouseClick = null; - renderingContext.clickedItem = null; - } + maintainRenderingContext(); final int millisecondsPassedSinceLastUpdate = getMillisecondsPassedSinceLastUpdate(); @@ -249,13 +234,30 @@ public class ViewPanel extends JPanel implements ComponentListener { } // abort rendering if window size is invalid - if ((getWidth() <= 0) || (getHeight() <= 0)) - renderFrame = false; - - if (renderFrame) { + if ((getWidth() > 0) && (getHeight() > 0) && renderFrame) { renderFrame(); handleDetectedComponentMouseEvents(); } + + } + + private void maintainRenderingContext() { + int panelWidth = getWidth(); + int panelHeight = getHeight(); + + if (panelWidth <= 0 || panelHeight <=0){ + renderingContext = null; + return; + } + + if ((renderingContext == null) + || (renderingContext.width != panelWidth) + || (renderingContext.height != panelHeight)) { + renderingContext = new RenderingContext(panelWidth, panelHeight); + } + + renderingContext.mouseEvent = null; + renderingContext.objectUnderMouse = null; } private boolean notifyViewRenderListeners(int millisecondsPassedSinceLastUpdate) { diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/HIDInputTracker.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/HIDInputTracker.java index ee625d5..5bf7927 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/HIDInputTracker.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/HIDInputTracker.java @@ -11,7 +11,6 @@ package eu.svjatoslav.sixth.e3d.gui.humaninput; import eu.svjatoslav.sixth.e3d.geometry.Point2D; import eu.svjatoslav.sixth.e3d.gui.Avatar; -import eu.svjatoslav.sixth.e3d.gui.RenderingContext; import eu.svjatoslav.sixth.e3d.gui.ViewPanel; import eu.svjatoslav.sixth.e3d.gui.ViewRenderListener; @@ -34,7 +33,7 @@ public class HIDInputTracker implements * */ private final Map pressedKeysToPressedTimeMap = new HashMap<>(); - private final List detectedMouseClicks = new ArrayList<>(); + private final List detectedMouseEvents = new ArrayList<>(); private final List detectedKeyEvents = new ArrayList<>(); private int wheelMovedDirection = 0; private Point2D mouseDraggedDirection = new Point2D(); @@ -118,37 +117,41 @@ public class HIDInputTracker implements * @return true if view needs to be repainted. */ private synchronized boolean handleMouseClicksAndHover(final ViewPanel viewPanel) { - MouseClick unprocessedMouseClick = findUnprocessedMouseClick(); + MouseEvent mouseEventAndLocationToTrace = getMouseEventAndLocationToTrace(viewPanel); + if (mouseEventAndLocationToTrace != null) + { + viewPanel.getRenderingContext().mouseEvent = mouseEventAndLocationToTrace; + return true; + } + return false; + } - if (unprocessedMouseClick != null) { - viewPanel.getRenderingContext().mouseClick = unprocessedMouseClick; - return false; + private MouseEvent getMouseEventAndLocationToTrace(ViewPanel viewPanel) { + MouseEvent unprocessedMouseEvent = findClickLocationToTrace(); + if (unprocessedMouseEvent != null) { + return unprocessedMouseEvent; } else - return handleMouseHovering(viewPanel); + return getHoverLocationToTrace(viewPanel); } - private MouseClick findUnprocessedMouseClick() { - synchronized (detectedMouseClicks) { - if (detectedMouseClicks.isEmpty()) + private MouseEvent findClickLocationToTrace() { + synchronized (detectedMouseEvents) { + if (detectedMouseEvents.isEmpty()) return null; - return detectedMouseClicks.remove(0); + return detectedMouseEvents.remove(0); } } - private boolean handleMouseHovering(ViewPanel viewPanel) { - if (currentMouseLocation != null) { - RenderingContext renderingContext = viewPanel.getRenderingContext(); - if (renderingContext != null) - renderingContext.mouseClick = new MouseClick(currentMouseLocation, 0); - // mouse click with button 0 amounts to mouse hovering event - } - + private MouseEvent getHoverLocationToTrace(ViewPanel viewPanel) { if (mouseMoved) { mouseMoved = false; - return true; - } else - return false; + if (currentMouseLocation != null) { + return new MouseEvent(currentMouseLocation, 0); + // mouse click with button 0 amounts to mouse hovering event + } + } + return null; } boolean isKeyPressed(final int keyCode) { @@ -176,9 +179,9 @@ public class HIDInputTracker implements } @Override - public void mouseClicked(final MouseEvent e) { - synchronized (detectedMouseClicks) { - detectedMouseClicks.add(new MouseClick(e.getX(), e.getY(), e.getButton())); + public void mouseClicked(final java.awt.event.MouseEvent e) { + synchronized (detectedMouseEvents) { + detectedMouseEvents.add(new MouseEvent(e.getX(), e.getY(), e.getButton())); } } @@ -197,24 +200,24 @@ public class HIDInputTracker implements } @Override - public void mouseEntered(final MouseEvent e) { + public void mouseEntered(final java.awt.event.MouseEvent e) { mouseWithinWindow = true; } @Override - public synchronized void mouseExited(final MouseEvent e) { + public synchronized void mouseExited(final java.awt.event.MouseEvent e) { mouseWithinWindow = false; currentMouseLocation = null; } @Override - public synchronized void mouseMoved(final MouseEvent e) { + public synchronized void mouseMoved(final java.awt.event.MouseEvent e) { currentMouseLocation = new Point2D(e.getX(), e.getY()); mouseMoved = true; } @Override - public void mousePressed(final MouseEvent e) { + public void mousePressed(final java.awt.event.MouseEvent e) { } @Override diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusStack.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusStack.java index 4ee7ed8..7690bab 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusStack.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusStack.java @@ -40,16 +40,20 @@ public class KeyboardFocusStack { currentUserInputHandler.focusReceived(viewPanel); } - public void pushFocusOwner(final UserInputHandler newInputHandler) { + public boolean pushFocusOwner(final UserInputHandler newInputHandler) { + boolean updateNeeded = false; + if (currentUserInputHandler == newInputHandler) - return; + return false; if (currentUserInputHandler != null) { - currentUserInputHandler.focusLost(viewPanel); + updateNeeded = currentUserInputHandler.focusLost(viewPanel); inputHandlers.push(currentUserInputHandler); } currentUserInputHandler = newInputHandler; - currentUserInputHandler.focusReceived(viewPanel); + updateNeeded |= currentUserInputHandler.focusReceived(viewPanel); + + return updateNeeded; } } diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseClick.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseEvent.java similarity index 82% rename from src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseClick.java rename to src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseEvent.java index fd82552..6589ac7 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseClick.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseEvent.java @@ -11,7 +11,7 @@ package eu.svjatoslav.sixth.e3d.gui.humaninput; import eu.svjatoslav.sixth.e3d.geometry.Point2D; -public class MouseClick { +public class MouseEvent { public Point2D coordinate; @@ -21,11 +21,11 @@ public class MouseClick { */ public int button; - public MouseClick(final int x, final int y, final int button) { + public MouseEvent(final int x, final int y, final int button) { this(new Point2D(x, y), button); } - public MouseClick(final Point2D coordinate, final int button) { + public MouseEvent(final Point2D coordinate, final int button) { this.coordinate = coordinate; this.button = button; } diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseInteractionController.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseInteractionController.java index f2c84b2..75abbaf 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseInteractionController.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseInteractionController.java @@ -13,17 +13,20 @@ public interface MouseInteractionController { /** * Called when mouse is clicked on component + * @return true if view update is needed. */ - void mouseClicked(); + boolean mouseClicked(); /** * Called when mouse gets over given component. + * @return true if view update is needed. */ - void mouseEntered(); + boolean mouseEntered(); /** * Called when mouse leaves screen area occupied by component. + * @return true if view update is needed. */ - void mouseExited(); + boolean mouseExited(); } diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/solidpolygon/SolidPolygon.java b/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/solidpolygon/SolidPolygon.java index 00ae317..e45a991 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/solidpolygon/SolidPolygon.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/solidpolygon/SolidPolygon.java @@ -103,10 +103,10 @@ public class SolidPolygon extends AbstractCoordinateShape { onScreenPoint3.roundToInteger(); if (mouseInteractionController != null) - if (context.mouseClick != null) - if (Polygon.pointWithinPolygon(context.mouseClick.coordinate, + if (context.mouseEvent != null) + if (Polygon.pointWithinPolygon(context.mouseEvent.coordinate, onScreenPoint1, onScreenPoint2, onScreenPoint3)) - context.clickedItem = mouseInteractionController; + context.objectUnderMouse = mouseInteractionController; if (color.isTransparent()) return; diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/texturedpolygon/TexturedPolygon.java b/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/texturedpolygon/TexturedPolygon.java index 686244c..cafcbbf 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/texturedpolygon/TexturedPolygon.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/texturedpolygon/TexturedPolygon.java @@ -11,7 +11,6 @@ package eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.texturedpolygon; import eu.svjatoslav.sixth.e3d.geometry.Point2D; import eu.svjatoslav.sixth.e3d.geometry.Point3D; -import eu.svjatoslav.sixth.e3d.geometry.Polygon; import eu.svjatoslav.sixth.e3d.gui.RenderingContext; import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractCoordinateShape; import eu.svjatoslav.sixth.e3d.renderer.raster.slicer.PolygonCoordinate; @@ -20,6 +19,8 @@ import eu.svjatoslav.sixth.e3d.renderer.raster.texture.TextureBitmap; import java.awt.*; +import static eu.svjatoslav.sixth.e3d.geometry.Polygon.pointWithinPolygon; + public class TexturedPolygon extends AbstractCoordinateShape { public final Texture texture; @@ -140,11 +141,11 @@ public class TexturedPolygon extends AbstractCoordinateShape { projectedPoint3.roundToInteger(); if (mouseInteractionController != null) - if (renderBuffer.mouseClick != null) - if (Polygon.pointWithinPolygon( - renderBuffer.mouseClick.coordinate, projectedPoint1, + if (renderBuffer.mouseEvent != null) + if (pointWithinPolygon( + renderBuffer.mouseEvent.coordinate, projectedPoint1, projectedPoint2, projectedPoint3)) - renderBuffer.clickedItem = mouseInteractionController; + renderBuffer.objectUnderMouse = mouseInteractionController; // Show polygon boundaries (for debugging) if (showBorders) -- 2.20.1