Optimized frame repainting. Fixed mouse click processing.
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 22 Jul 2018 22:12:39 +0000 (01:12 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 22 Jul 2018 22:12:39 +0000 (01:12 +0300)
src/main/java/eu/svjatoslav/sixth/e3d/gui/GuiComponent.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/RenderingContext.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewPanel.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/HIDInputTracker.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusStack.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseClick.java [deleted file]
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseEvent.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseInteractionController.java
src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/solidpolygon/SolidPolygon.java
src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/texturedpolygon/TexturedPolygon.java

index 70350e0..62e8eaf 100644 (file)
@@ -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) {
index afbe22d..2603c11 100644 (file)
@@ -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;
index ea55a31..84d4529 100755 (executable)
@@ -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) {
index ee625d5..5bf7927 100755 (executable)
@@ -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
      * </pre>
      */
     private final Map<Integer, Long> pressedKeysToPressedTimeMap = new HashMap<>();
-    private final List<MouseClick> detectedMouseClicks = new ArrayList<>();
+    private final List<MouseEvent> detectedMouseEvents = new ArrayList<>();
     private final List<KeyEvent> detectedKeyEvents = new ArrayList<>();
     private int wheelMovedDirection = 0;
     private Point2D mouseDraggedDirection = new Point2D();
@@ -118,37 +117,41 @@ public class HIDInputTracker implements
      * @return <code>true</code> 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
index 4ee7ed8..7690bab 100644 (file)
@@ -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/MouseClick.java
deleted file mode 100644 (file)
index fd82552..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Sixth 3D engine. Copyright ©2012-2018, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 3 of the GNU Lesser General Public License
- * or later as published by the Free Software Foundation.
- *
- */
-
-package eu.svjatoslav.sixth.e3d.gui.humaninput;
-
-import eu.svjatoslav.sixth.e3d.geometry.Point2D;
-
-public class MouseClick {
-
-    public Point2D coordinate;
-
-    /**
-     * Indicates pressed mouse button. Except 0 that simply means mouse over
-     * given region.
-     */
-    public int button;
-
-    public MouseClick(final int x, final int y, final int button) {
-        this(new Point2D(x, y), button);
-    }
-
-    public MouseClick(final Point2D coordinate, final int button) {
-        this.coordinate = coordinate;
-        this.button = button;
-    }
-
-}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseEvent.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/MouseEvent.java
new file mode 100644 (file)
index 0000000..6589ac7
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Sixth 3D engine. Copyright ©2012-2018, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 3 of the GNU Lesser General Public License
+ * or later as published by the Free Software Foundation.
+ *
+ */
+
+package eu.svjatoslav.sixth.e3d.gui.humaninput;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point2D;
+
+public class MouseEvent {
+
+    public Point2D coordinate;
+
+    /**
+     * Indicates pressed mouse button. Except 0 that simply means mouse over
+     * given region.
+     */
+    public int button;
+
+    public MouseEvent(final int x, final int y, final int button) {
+        this(new Point2D(x, y), button);
+    }
+
+    public MouseEvent(final Point2D coordinate, final int button) {
+        this.coordinate = coordinate;
+        this.button = button;
+    }
+
+}
index f2c84b2..75abbaf 100644 (file)
@@ -13,17 +13,20 @@ public interface MouseInteractionController {
 
     /**
      * Called when mouse is clicked on component
+     * @return <code>true</code> if view update is needed.
      */
-    void mouseClicked();
+    boolean mouseClicked();
 
     /**
      * Called when mouse gets over given component.
+     * @return <code>true</code> if view update is needed.
      */
-    void mouseEntered();
+    boolean mouseEntered();
 
     /**
      * Called when mouse leaves screen area occupied by component.
+     * @return <code>true</code> if view update is needed.
      */
-    void mouseExited();
+    boolean mouseExited();
 
 }
index 00ae317..e45a991 100644 (file)
@@ -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;
index 686244c..cafcbbf 100644 (file)
@@ -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)