Code refactoring.
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 22 Jul 2018 20:36:06 +0000 (23:36 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 22 Jul 2018 20:36:06 +0000 (23:36 +0300)
src/main/java/eu/svjatoslav/sixth/e3d/gui/Avatar.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/GuiComponent.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewFrame.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewPanel.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/HIDInputTracker.java [new file with mode: 0755]
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusStack.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusTracker.java [deleted file]
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/UserInputTracker.java [deleted file]
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationTracker.java [deleted file]
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationUserInputTracker.java [new file with mode: 0644]

index 52d78b2..852dc97 100755 (executable)
@@ -70,7 +70,7 @@ public class Avatar implements ViewRenderListener {
     public boolean beforeRender(final ViewPanel viewPanel, final int millisecondsSinceLastFrame) {
 
         final Point3D locationBeforeUpdate = new Point3D(location);
-        translateAvatarLocation(millisecondsSinceLastFrame);
+        translateAvatarLocationBasedOnMovementVector(millisecondsSinceLastFrame);
         applyFrictionToUserMovement(millisecondsSinceLastFrame);
         return isFrameRepaintNeeded(locationBeforeUpdate);
     }
@@ -139,7 +139,7 @@ public class Avatar implements ViewRenderListener {
      *                                         Therefore we take frame rendering time into account when translating
      *                                         avatar between consecutive frames.
      */
-    private void translateAvatarLocation(int millisecondsPassedSinceLastFrame) {
+    private void translateAvatarLocationBasedOnMovementVector(int millisecondsPassedSinceLastFrame) {
         location.x -= (float) sin(getAngleXZ())
                 * getMovementVector().z * SPEED_MULTIPLIER
                 * millisecondsPassedSinceLastFrame;
index 75dbbf4..70350e0 100644 (file)
@@ -95,7 +95,7 @@ public class GuiComponent extends AbstractCompositeShape implements
     @Override
     public boolean keyPressed(final KeyEvent event, final ViewPanel viewPanel) {
         if (event.getKeyChar() == KeyboardHelper.ESC)
-            viewPanel.getKeyboardFocusTracker().popFocusOwner();
+            viewPanel.getKeyboardFocusStack().popFocusOwner();
         return true;
     }
 
@@ -106,7 +106,7 @@ public class GuiComponent extends AbstractCompositeShape implements
 
     @Override
     public void mouseClicked() {
-        viewPanel.getKeyboardFocusTracker().setFocusOwner(this);
+        viewPanel.getKeyboardFocusStack().pushFocusOwner(this);
     }
 
     @Override
index 874673f..1383c72 100755 (executable)
@@ -46,7 +46,7 @@ public class ViewFrame extends JFrame implements WindowListener {
         addWindowListener(this);
     }
 
-    public void addResizeListener() {
+    private void addResizeListener() {
         addComponentListener(new ComponentListener() {
             // This method is called after the component's size changes
             @Override
index 6fda153..b23bf5b 100755 (executable)
@@ -9,9 +9,9 @@
 
 package eu.svjatoslav.sixth.e3d.gui;
 
-import eu.svjatoslav.sixth.e3d.gui.humaninput.KeyboardFocusTracker;
+import eu.svjatoslav.sixth.e3d.gui.humaninput.KeyboardFocusStack;
 import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseInteractionController;
-import eu.svjatoslav.sixth.e3d.gui.humaninput.UserInputTracker;
+import eu.svjatoslav.sixth.e3d.gui.humaninput.HIDInputTracker;
 import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
 
 import javax.swing.*;
@@ -27,9 +27,9 @@ import java.util.Timer;
  */
 public class ViewPanel extends JPanel implements ComponentListener {
     private static final long serialVersionUID = 1683277888885045387L;
-    private final UserInputTracker userInputTracker = new UserInputTracker(this);
-    private final KeyboardFocusTracker keyboardFocusTracker = new KeyboardFocusTracker(
-            this);
+    public Color backgroundColor = Color.BLACK;
+    private final HIDInputTracker HIDInputTracker = new HIDInputTracker(this);
+    private final KeyboardFocusStack keyboardFocusStack = new KeyboardFocusStack(this);
     private final Avatar avatar = new Avatar();
     private final ShapeCollection rootShapeCollection = new ShapeCollection();
     private final List<ViewRenderListener> viewRenderListeners = new ArrayList<>();
@@ -56,7 +56,7 @@ public class ViewPanel extends JPanel implements ComponentListener {
     private boolean viewRepaintNeeded = true;
     public ViewPanel() {
         viewRenderListeners.add(avatar);
-        viewRenderListeners.add(userInputTracker);
+        viewRenderListeners.add(HIDInputTracker);
 
         initializePanelLayout();
 
@@ -69,16 +69,16 @@ public class ViewPanel extends JPanel implements ComponentListener {
         return avatar;
     }
 
-    public KeyboardFocusTracker getKeyboardFocusTracker() {
-        return keyboardFocusTracker;
+    public KeyboardFocusStack getKeyboardFocusStack() {
+        return keyboardFocusStack;
     }
 
     public ShapeCollection getRootShapeCollection() {
         return rootShapeCollection;
     }
 
-    public UserInputTracker getUserInputTracker() {
-        return userInputTracker;
+    public HIDInputTracker getHIDInputTracker() {
+        return HIDInputTracker;
     }
 
     public void addViewUpdateListener(final ViewRenderListener listener) {
@@ -120,10 +120,6 @@ public class ViewPanel extends JPanel implements ComponentListener {
         return new java.awt.Dimension(640, 480);
     }
 
-    public RenderingContext getRenderBuffer() {
-        return renderingContext;
-    }
-
     public RenderingContext getRenderingContext() {
         return renderingContext;
     }
@@ -163,29 +159,31 @@ public class ViewPanel extends JPanel implements ComponentListener {
         requestFocusInWindow();
     }
 
-    public void renderFrame() {
-        // build new render buffer if needed, this happens when window was just
-        // created or resized
-        if ((renderingContext == null)
-                || (renderingContext.width != getWidth())
-                || (renderingContext.height != getHeight()))
+    private void renderFrame() {
+        if (isNewRenderingContextNeeded())
             renderingContext = new RenderingContext(getWidth(), getHeight());
 
-        // clear drawing area
-        {
-            renderingContext.graphics.setColor(Color.BLACK);
-            renderingContext.graphics.fillRect(0, 0, getWidth(), getHeight());
-        }
-
         // paint root geometry collection to the offscreen render buffer
+        clearCanvas();
         rootShapeCollection.paint(this, renderingContext);
 
-        // draw rendered offscreen image to visible screen
+        // draw rendered offscreen buffer to visible screen
         final Graphics graphics = getGraphics();
         if (graphics != null)
             graphics.drawImage(renderingContext.bufferedImage, 0, 0, null);
     }
 
+    private void clearCanvas() {
+        renderingContext.graphics.setColor(backgroundColor);
+        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.
@@ -233,42 +231,47 @@ public class ViewPanel extends JPanel implements ComponentListener {
      * It tells view to update itself. View can decide if actual re-rendering of
      * graphics is needed.
      */
-    public void updateView() {
+    void updateView() {
         if (renderingContext != null) {
             renderingContext.mouseClick = null;
             renderingContext.clickedItem = null;
         }
 
-        // compute time passed since last view update
-        final long currentTime = System.currentTimeMillis();
+        final int millisecondsPassedSinceLastUpdate = getMillisecondsPassedSinceLastUpdate();
 
-        if (lastUpdateMillis == 0) {
-            lastUpdateMillis = currentTime;
-            return;
+        boolean renderFrame = notifyViewRenderListeners(millisecondsPassedSinceLastUpdate);
+
+        if (viewRepaintNeeded) {
+            viewRepaintNeeded = false;
+            renderFrame = true;
         }
 
-        final int millisecondsPassedSinceLastUpdate = (int) (currentTime - lastUpdateMillis);
-        lastUpdateMillis = currentTime;
+        // abort rendering if window size is invalid
+        if ((getWidth() <= 0) || (getHeight() <= 0))
+            renderFrame = false;
 
-        // notify update listeners
-        boolean reRenderFrame = false;
+        if (renderFrame) {
+            renderFrame();
+            handleDetectedComponentMouseEvents();
+        }
+    }
 
+    private boolean notifyViewRenderListeners(int millisecondsPassedSinceLastUpdate) {
+        boolean reRenderFrame = false;
         for (final ViewRenderListener listener : viewRenderListeners)
             if (listener.beforeRender(this, millisecondsPassedSinceLastUpdate))
                 reRenderFrame = true;
+        return reRenderFrame;
+    }
 
-        // abort rendering if window size is invalid
-        if ((getWidth() <= 0) || (getHeight() <= 0))
-            return;
+    private int getMillisecondsPassedSinceLastUpdate() {
+        final long currentTime = System.currentTimeMillis();
 
-        if (viewRepaintNeeded) {
-            viewRepaintNeeded = false;
-            reRenderFrame = true;
-        }
+        if (lastUpdateMillis == 0)
+            lastUpdateMillis = currentTime;
 
-        if (reRenderFrame) {
-            renderFrame();
-            handleDetectedComponentMouseEvents();
-        }
+        final int millisecondsPassedSinceLastUpdate = (int) (currentTime - lastUpdateMillis);
+        lastUpdateMillis = currentTime;
+        return 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
new file mode 100755 (executable)
index 0000000..6015ee7
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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;
+import eu.svjatoslav.sixth.e3d.gui.Avatar;
+import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
+import eu.svjatoslav.sixth.e3d.gui.ViewRenderListener;
+
+import javax.swing.*;
+import java.awt.event.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class HIDInputTracker implements
+        MouseMotionListener, KeyListener, MouseListener, MouseWheelListener, ViewRenderListener {
+
+    /**
+     * <pre>
+     * Key is keyboard key code.
+     * Value is system milliseconds when key was pressed.
+     *
+     * So by reading the map one can determine currently pressed keys as well as duration.
+     * </pre>
+     */
+    private final Map<Integer, Long> pressedKeysToPressedTimeMap = new HashMap<>();
+    private final List<MouseClick> detectedMouseClicks = new ArrayList<>();
+    private final List<KeyEvent> detectedKeyEvents = new ArrayList<>();
+    private int wheelMovedDirection = 0;
+    private Point2D mouseDraggedDirection = new Point2D();
+    private Point2D oldMouseCoordinatesWhenDragging;
+    private ViewPanel viewPanel;
+    private Point2D currentMouseLocation;
+    private boolean mouseMoved;
+    private boolean mouseWithinWindow = false;
+
+    public HIDInputTracker(final ViewPanel viewPanel) {
+        this.viewPanel = viewPanel;
+        bind(viewPanel);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean beforeRender(final ViewPanel viewPanel, final int millisecondsSinceLastFrame) {
+        boolean viewUpdateNeeded = handleKeyboardEvents();
+        viewUpdateNeeded |= handleMouseClicksAndHover(viewPanel);
+        viewUpdateNeeded |= handleMouseDragging();
+        viewUpdateNeeded |= handleMouseVerticalScrolling();
+        return viewUpdateNeeded;
+    }
+
+    private void bind(final JPanel panel) {
+        panel.addMouseMotionListener(this);
+
+        panel.addKeyListener(this);
+
+        panel.addMouseListener(this);
+
+        panel.addMouseWheelListener(this);
+    }
+
+    /**
+     * @return <code>true</code> if view needs to be repainted.
+     */
+    private boolean handleKeyboardEvents() {
+        final UserInputHandler currentFocusOwner = viewPanel.getKeyboardFocusStack().getCurrentFocusOwner();
+        ArrayList<KeyEvent> unprocessedKeyboardEvents = getUnprocessedKeyboardEvents();
+
+        return currentFocusOwner != null
+                && forwardKeyboardEventsToFocusOwner(currentFocusOwner, unprocessedKeyboardEvents);
+    }
+
+    private ArrayList<KeyEvent> getUnprocessedKeyboardEvents() {
+        synchronized (detectedKeyEvents) {
+            ArrayList<KeyEvent> result = new ArrayList<>(detectedKeyEvents);
+            detectedKeyEvents.clear();
+            return result;
+        }
+    }
+
+    /**
+     * @return <code>true</code> if view update is needed.
+     */
+    private boolean forwardKeyboardEventsToFocusOwner(
+            UserInputHandler currentFocusOwner, ArrayList<KeyEvent> keyEvents) {
+        boolean viewUpdateNeeded = false;
+
+        for (KeyEvent keyEvent : keyEvents)
+            viewUpdateNeeded |= processKeyEvent(currentFocusOwner, keyEvent);
+
+        return viewUpdateNeeded;
+    }
+
+    private boolean processKeyEvent(UserInputHandler currentFocusOwner, KeyEvent keyEvent) {
+        switch (keyEvent.getID()) {
+            case KeyEvent.KEY_PRESSED:
+                return currentFocusOwner.keyPressed(keyEvent, viewPanel);
+
+            case KeyEvent.KEY_RELEASED:
+                return currentFocusOwner.keyReleased(keyEvent, viewPanel);
+        }
+        return false;
+    }
+
+    /**
+     * @return <code>true</code> if view needs to be repainted.
+     */
+    private synchronized boolean handleMouseClicksAndHover(final ViewPanel viewPanel) {
+        MouseClick unprocessedMouseClick = findUnprocessedMouseClick();
+
+        if (unprocessedMouseClick != null) {
+            viewPanel.getRenderingContext().mouseClick = unprocessedMouseClick;
+            return false;
+        } else
+            return handleMouseHovering(viewPanel);
+    }
+
+    private MouseClick findUnprocessedMouseClick() {
+        synchronized (detectedMouseClicks) {
+            if (detectedMouseClicks.isEmpty())
+                return null;
+
+            return detectedMouseClicks.remove(0);
+        }
+    }
+
+    private boolean handleMouseHovering(ViewPanel viewPanel) {
+        if (currentMouseLocation != null)
+            // mouse click with button 0 amounts to mouse hovering event
+            viewPanel.getRenderingContext().mouseClick = new MouseClick(currentMouseLocation, 0);
+
+        if (mouseMoved) {
+            mouseMoved = false;
+            return true;
+        } else
+            return false;
+    }
+
+    boolean isKeyPressed(final int keyCode) {
+        return pressedKeysToPressedTimeMap.containsKey(keyCode);
+    }
+
+    @Override
+    public void keyPressed(final KeyEvent evt) {
+        synchronized (detectedKeyEvents) {
+            pressedKeysToPressedTimeMap.put(evt.getKeyCode(), System.currentTimeMillis());
+            detectedKeyEvents.add(evt);
+        }
+    }
+
+    @Override
+    public void keyReleased(final KeyEvent evt) {
+        synchronized (detectedKeyEvents) {
+            pressedKeysToPressedTimeMap.remove(evt.getKeyCode());
+            detectedKeyEvents.add(evt);
+        }
+    }
+
+    @Override
+    public void keyTyped(final KeyEvent e) {
+    }
+
+    @Override
+    public void mouseClicked(final MouseEvent e) {
+        synchronized (detectedMouseClicks) {
+            detectedMouseClicks.add(new MouseClick(e.getX(), e.getY(), e.getButton()));
+        }
+    }
+
+    @Override
+    public void mouseDragged(final java.awt.event.MouseEvent evt) {
+        final Point2D mouseLocation = new Point2D(evt.getX(), evt.getY());
+
+        if (oldMouseCoordinatesWhenDragging == null) {
+            oldMouseCoordinatesWhenDragging = mouseLocation;
+            return;
+        }
+
+        mouseDraggedDirection.add(mouseLocation.clone().subtract(oldMouseCoordinatesWhenDragging));
+
+        oldMouseCoordinatesWhenDragging = mouseLocation;
+    }
+
+    @Override
+    public void mouseEntered(final MouseEvent e) {
+        mouseWithinWindow = true;
+    }
+
+    @Override
+    public synchronized void mouseExited(final MouseEvent e) {
+        mouseWithinWindow = false;
+        currentMouseLocation = null;
+    }
+
+    @Override
+    public synchronized void mouseMoved(final MouseEvent e) {
+        currentMouseLocation = new Point2D(e.getX(), e.getY());
+        mouseMoved = true;
+    }
+
+    @Override
+    public void mousePressed(final MouseEvent e) {
+    }
+
+    @Override
+    public void mouseReleased(final java.awt.event.MouseEvent evt) {
+        oldMouseCoordinatesWhenDragging = null;
+    }
+
+    @Override
+    public void mouseWheelMoved(final java.awt.event.MouseWheelEvent evt) {
+        wheelMovedDirection += evt.getWheelRotation();
+    }
+
+    /**
+     * @return <code>true</code> if view needs to be repainted.
+     */
+    private boolean handleMouseVerticalScrolling() {
+        final Avatar avatar = viewPanel.getAvatar();
+        final double actualAcceleration = 50 * avatar.avatarAcceleration * (1 + (avatar.getMovementSpeed() / 10));
+        avatar.getMovementVector().y += (wheelMovedDirection * actualAcceleration);
+        avatar.enforceSpeedLimit();
+        boolean repaintNeeded = wheelMovedDirection != 0;
+        wheelMovedDirection = 0;
+        return repaintNeeded;
+    }
+
+    /**
+     * @return <code>true</code> if view needs to be repainted.
+     */
+    private boolean handleMouseDragging() {
+        // TODO: need to detect whether user moved mouse or touch screen
+
+        final Avatar avatar = viewPanel.getAvatar();
+        // for mouse
+        avatar.setAngleXZ(avatar.getAngleXZ() - ((float) mouseDraggedDirection.x / 50));
+        avatar.setAngleYZ(avatar.getAngleYZ() - ((float) mouseDraggedDirection.y / 50));
+
+        // for touch screen
+        // avatar.setAngleXZ(avatar.getAngleXZ() + ((float)
+        // mouseDraggedDirection.x / 50));
+        // avatar.setAngleYZ(avatar.getAngleYZ() + ((float)
+        // mouseDraggedDirection.y / 50));
+
+        boolean viewUpdateNeeded = !mouseDraggedDirection.isZero();
+        mouseDraggedDirection.zero();
+        return viewUpdateNeeded;
+    }
+
+}
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
new file mode 100644 (file)
index 0000000..4ee7ed8
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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.gui.ViewPanel;
+
+import java.util.Stack;
+
+public class KeyboardFocusStack {
+
+    private final ViewPanel viewPanel;
+    private WorldNavigationUserInputTracker defaultInputHandler = new WorldNavigationUserInputTracker();
+    private Stack<UserInputHandler> inputHandlers = new Stack<>();
+    private UserInputHandler currentUserInputHandler;
+
+    public KeyboardFocusStack(final ViewPanel viewPanel) {
+        this.viewPanel = viewPanel;
+        pushFocusOwner(defaultInputHandler);
+    }
+
+    public UserInputHandler getCurrentFocusOwner() {
+        return currentUserInputHandler;
+    }
+
+    public void popFocusOwner() {
+        if (currentUserInputHandler != null)
+            currentUserInputHandler.focusLost(viewPanel);
+
+        if (inputHandlers.isEmpty())
+            return;
+
+        currentUserInputHandler = inputHandlers.pop();
+        currentUserInputHandler.focusReceived(viewPanel);
+    }
+
+    public void pushFocusOwner(final UserInputHandler newInputHandler) {
+        if (currentUserInputHandler == newInputHandler)
+            return;
+
+        if (currentUserInputHandler != null) {
+            currentUserInputHandler.focusLost(viewPanel);
+            inputHandlers.push(currentUserInputHandler);
+        }
+
+        currentUserInputHandler = newInputHandler;
+        currentUserInputHandler.focusReceived(viewPanel);
+    }
+}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusTracker.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusTracker.java
deleted file mode 100644 (file)
index 65e9374..0000000
+++ /dev/null
@@ -1,59 +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.gui.ViewPanel;
-
-import java.util.Stack;
-
-public class KeyboardFocusTracker {
-
-    private final ViewPanel viewPanel;
-    WorldNavigationTracker defaultInputHandler = new WorldNavigationTracker();
-    Stack<UserInputHandler> inputHandlers = new Stack<>();
-    private UserInputHandler currentUserInputHandler;
-
-    public KeyboardFocusTracker(final ViewPanel viewPanel) {
-        this.viewPanel = viewPanel;
-        setFocusOwner(defaultInputHandler);
-    }
-
-    public UserInputHandler getCurrentFocusOwner() {
-        return currentUserInputHandler;
-    }
-
-    public void popFocusOwner() {
-        if (currentUserInputHandler == null)
-            return;
-
-        if (inputHandlers.isEmpty())
-            return;
-
-        currentUserInputHandler.focusLost(viewPanel);
-
-        currentUserInputHandler = inputHandlers.pop();
-
-        currentUserInputHandler.focusReceived(viewPanel);
-    }
-
-    public void setFocusOwner(final UserInputHandler inputHandler) {
-        if (currentUserInputHandler == inputHandler)
-            return;
-
-        if (currentUserInputHandler != null) {
-            currentUserInputHandler.focusLost(viewPanel);
-            inputHandlers.push(currentUserInputHandler);
-        }
-
-        currentUserInputHandler = inputHandler;
-
-        currentUserInputHandler.focusReceived(viewPanel);
-    }
-}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/UserInputTracker.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/UserInputTracker.java
deleted file mode 100755 (executable)
index 3060691..0000000
+++ /dev/null
@@ -1,263 +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;
-import eu.svjatoslav.sixth.e3d.gui.Avatar;
-import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
-import eu.svjatoslav.sixth.e3d.gui.ViewRenderListener;
-
-import javax.swing.*;
-import java.awt.event.*;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class UserInputTracker implements
-        MouseMotionListener, KeyListener, MouseListener, MouseWheelListener, ViewRenderListener {
-
-    /**
-     * <pre>
-     * Key is keyboard key code.
-     * Value is system milliseconds when key was pressed.
-     *
-     * So by reading the map one can determine currently pressed keys as well as duration.
-     * </pre>
-     */
-    private final Map<Integer, Long> pressedKeysToPressedTimeMap = new HashMap<>();
-    private final List<MouseClick> detectedMouseClicks = new ArrayList<>();
-    private final List<KeyEvent> detectedKeyEvents = new ArrayList<>();
-    private int wheelMovedDirection = 0;
-    private Point2D mouseDraggedDirection = new Point2D();
-    private Point2D oldMouseCoordinatesWhenDragging;
-    private ViewPanel viewPanel;
-    private Point2D currentMouseLocation;
-    private boolean mouseMoved;
-    private boolean mouseWithinWindow = false;
-
-    public UserInputTracker(final ViewPanel viewPanel) {
-        this.viewPanel = viewPanel;
-        bind(viewPanel);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean beforeRender(final ViewPanel viewPanel, final int millisecondsSinceLastFrame) {
-
-        boolean viewUpdateNeeded = handleKeyboardEvents();
-        viewUpdateNeeded |= handleMouseClicksAndHover(viewPanel);
-        viewUpdateNeeded |= handleMouseDragging();
-        viewUpdateNeeded |= handleMouseVerticalScrolling();
-
-        return viewUpdateNeeded;
-    }
-
-    private void bind(final JPanel panel) {
-        panel.addMouseMotionListener(this);
-
-        panel.addKeyListener(this);
-
-        panel.addMouseListener(this);
-
-        panel.addMouseWheelListener(this);
-    }
-
-    /**
-     * @return <code>true</code> if view needs to be repainted.
-     */
-    private boolean handleKeyboardEvents() {
-        final UserInputHandler currentFocusOwner = viewPanel.getKeyboardFocusTracker().getCurrentFocusOwner();
-        ArrayList<KeyEvent> unprocessedKeyboardEvents = getUnprocessedKeyboardEvents();
-
-        return currentFocusOwner == null ? false :
-                forwardKeyboardEventsToFocusOwner(currentFocusOwner, unprocessedKeyboardEvents);
-    }
-
-    private ArrayList<KeyEvent> getUnprocessedKeyboardEvents() {
-        synchronized (detectedKeyEvents) {
-            ArrayList<KeyEvent> result = new ArrayList<>(detectedKeyEvents);
-            detectedKeyEvents.clear();
-            return result;
-        }
-    }
-
-    /**
-     * @return <code>true</code> if view update is needed.
-     */
-    private boolean forwardKeyboardEventsToFocusOwner(
-            UserInputHandler currentFocusOwner, ArrayList<KeyEvent> keyEvents) {
-        boolean viewUpdateNeeded = false;
-
-        for (KeyEvent keyEvent : keyEvents)
-            viewUpdateNeeded |= processKeyEvent(currentFocusOwner, keyEvent);
-
-        return viewUpdateNeeded;
-    }
-
-    private boolean processKeyEvent(UserInputHandler currentFocusOwner, KeyEvent keyEvent) {
-        switch (keyEvent.getID()) {
-            case KeyEvent.KEY_PRESSED:
-                return currentFocusOwner.keyPressed(keyEvent, viewPanel);
-
-            case KeyEvent.KEY_RELEASED:
-                return currentFocusOwner.keyReleased(keyEvent, viewPanel);
-        }
-        return false;
-    }
-
-    /**
-     * @return <code>true</code> if view needs to be repainted.
-     */
-    private synchronized boolean handleMouseClicksAndHover(final ViewPanel viewPanel) {
-        MouseClick unprocessedMouseClick = findUnprocessedMouseClick();
-
-        if (unprocessedMouseClick != null) {
-            viewPanel.getRenderingContext().mouseClick = unprocessedMouseClick;
-            return false;
-        } else
-            return handleMouseHovering(viewPanel);
-    }
-
-    private MouseClick findUnprocessedMouseClick() {
-        synchronized (detectedMouseClicks) {
-            if (detectedMouseClicks.isEmpty())
-                return null;
-
-            return detectedMouseClicks.remove(0);
-        }
-    }
-
-    private boolean handleMouseHovering(ViewPanel viewPanel) {
-        if (currentMouseLocation != null)
-            // mouse click with button 0 amounts to mouse hovering event
-            viewPanel.getRenderingContext().mouseClick = new MouseClick(currentMouseLocation, 0);
-
-        if (mouseMoved) {
-            mouseMoved = false;
-            return true;
-        } else
-            return false;
-    }
-
-    boolean isKeyPressed(final int keyCode) {
-        return pressedKeysToPressedTimeMap.containsKey(keyCode);
-    }
-
-    @Override
-    public void keyPressed(final KeyEvent evt) {
-        synchronized (detectedKeyEvents) {
-            pressedKeysToPressedTimeMap.put(evt.getKeyCode(), System.currentTimeMillis());
-            detectedKeyEvents.add(evt);
-        }
-    }
-
-    @Override
-    public void keyReleased(final KeyEvent evt) {
-        synchronized (detectedKeyEvents) {
-            pressedKeysToPressedTimeMap.remove(evt.getKeyCode());
-            detectedKeyEvents.add(evt);
-        }
-    }
-
-    @Override
-    public void keyTyped(final KeyEvent e) {
-    }
-
-    @Override
-    public void mouseClicked(final MouseEvent e) {
-        synchronized (detectedMouseClicks) {
-            detectedMouseClicks.add(new MouseClick(e.getX(), e.getY(), e.getButton()));
-        }
-    }
-
-    @Override
-    public void mouseDragged(final java.awt.event.MouseEvent evt) {
-        final Point2D mouseLocation = new Point2D(evt.getX(), evt.getY());
-
-        if (oldMouseCoordinatesWhenDragging == null) {
-            oldMouseCoordinatesWhenDragging = mouseLocation;
-            return;
-        }
-
-        mouseDraggedDirection.add(mouseLocation.clone().subtract(oldMouseCoordinatesWhenDragging));
-
-        oldMouseCoordinatesWhenDragging = mouseLocation;
-    }
-
-    @Override
-    public void mouseEntered(final MouseEvent e) {
-        mouseWithinWindow = true;
-    }
-
-    @Override
-    public synchronized void mouseExited(final MouseEvent e) {
-        mouseWithinWindow = false;
-        currentMouseLocation = null;
-    }
-
-    @Override
-    public synchronized void mouseMoved(final MouseEvent e) {
-        currentMouseLocation = new Point2D(e.getX(), e.getY());
-        mouseMoved = true;
-    }
-
-    @Override
-    public void mousePressed(final MouseEvent e) {
-    }
-
-    @Override
-    public void mouseReleased(final java.awt.event.MouseEvent evt) {
-        oldMouseCoordinatesWhenDragging = null;
-    }
-
-    @Override
-    public void mouseWheelMoved(final java.awt.event.MouseWheelEvent evt) {
-        wheelMovedDirection += evt.getWheelRotation();
-    }
-
-    /**
-     * @return <code>true</code> if view needs to be repainted.
-     */
-    private boolean handleMouseVerticalScrolling() {
-        final Avatar avatar = viewPanel.getAvatar();
-        final double actualAcceleration = 50 * avatar.avatarAcceleration * (1 + (avatar.getMovementSpeed() / 10));
-        avatar.getMovementVector().y += (wheelMovedDirection * actualAcceleration);
-        avatar.enforceSpeedLimit();
-        boolean repaintNeeded = wheelMovedDirection != 0;
-        wheelMovedDirection = 0;
-        return repaintNeeded;
-    }
-
-    /**
-     * @return <code>true</code> if view needs to be repainted.
-     */
-    private boolean handleMouseDragging() {
-        // TODO: need to detect whether user moved mouse or touch screen
-
-        final Avatar avatar = viewPanel.getAvatar();
-        // for mouse
-        avatar.setAngleXZ(avatar.getAngleXZ() - ((float) mouseDraggedDirection.x / 50));
-        avatar.setAngleYZ(avatar.getAngleYZ() - ((float) mouseDraggedDirection.y / 50));
-
-        // for touch screen
-        // avatar.setAngleXZ(avatar.getAngleXZ() + ((float)
-        // mouseDraggedDirection.x / 50));
-        // avatar.setAngleYZ(avatar.getAngleYZ() + ((float)
-        // mouseDraggedDirection.y / 50));
-
-        boolean viewUpdateNeeded = !mouseDraggedDirection.isZero();
-        mouseDraggedDirection.zero();
-        return viewUpdateNeeded;
-    }
-
-}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationTracker.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationTracker.java
deleted file mode 100644 (file)
index 28d485c..0000000
+++ /dev/null
@@ -1,76 +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.gui.Avatar;
-import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
-import eu.svjatoslav.sixth.e3d.gui.textEditorComponent.KeyboardHelper;
-
-import java.awt.event.KeyEvent;
-
-public class WorldNavigationTracker implements UserInputHandler {
-
-    @Override
-    public boolean beforeRender(final ViewPanel viewPanel,
-                                final int millisecondsSinceLastFrame) {
-
-        trackKeys(millisecondsSinceLastFrame, viewPanel);
-        return false;
-    }
-
-    @Override
-    public boolean focusLost(final ViewPanel viewPanel) {
-        return false;
-    }
-
-    @Override
-    public boolean focusReceived(final ViewPanel viewContext) {
-        return false;
-    }
-
-    @Override
-    public boolean keyPressed(final KeyEvent event, final ViewPanel viewContext) {
-        return true;
-    }
-
-    @Override
-    public boolean keyReleased(final KeyEvent event, final ViewPanel viewContext) {
-        return true;
-    }
-
-    /**
-     * interpret currently pressed keys
-     */
-    public void trackKeys(final long millisecondsSinceLastFrame,
-                          final ViewPanel viewContext) {
-
-        final UserInputTracker inputTracker = viewContext.getUserInputTracker();
-
-        final Avatar avatar = viewContext.getAvatar();
-
-        final double actualAcceleration = millisecondsSinceLastFrame
-                * avatar.avatarAcceleration
-                * (1 + (avatar.getMovementSpeed() / 10));
-
-        if (inputTracker.isKeyPressed(KeyboardHelper.UP))
-            avatar.getMovementVector().z += actualAcceleration;
-
-        if (inputTracker.isKeyPressed(KeyboardHelper.DOWN))
-            avatar.getMovementVector().z -= actualAcceleration;
-
-        if (inputTracker.isKeyPressed(KeyboardHelper.RIGHT))
-            avatar.getMovementVector().x += actualAcceleration;
-
-        if (inputTracker.isKeyPressed(KeyboardHelper.LEFT))
-            avatar.getMovementVector().x -= actualAcceleration;
-
-        avatar.enforceSpeedLimit();
-    }
-}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationUserInputTracker.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationUserInputTracker.java
new file mode 100644 (file)
index 0000000..d80924c
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.gui.Avatar;
+import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
+import eu.svjatoslav.sixth.e3d.gui.textEditorComponent.KeyboardHelper;
+
+import java.awt.event.KeyEvent;
+
+public class WorldNavigationUserInputTracker implements UserInputHandler {
+
+    @Override
+    public boolean beforeRender(final ViewPanel viewPanel,
+                                final int millisecondsSinceLastFrame) {
+
+        trackKeys(millisecondsSinceLastFrame, viewPanel);
+        return false;
+    }
+
+    @Override
+    public boolean focusLost(final ViewPanel viewPanel) {
+        return false;
+    }
+
+    @Override
+    public boolean focusReceived(final ViewPanel viewContext) {
+        return false;
+    }
+
+    @Override
+    public boolean keyPressed(final KeyEvent event, final ViewPanel viewContext) {
+        return false;
+    }
+
+    @Override
+    public boolean keyReleased(final KeyEvent event, final ViewPanel viewContext) {
+        return false;
+    }
+
+    /**
+     * interpret currently pressed keys
+     */
+    private void trackKeys(final long millisecondsSinceLastFrame,
+                           final ViewPanel viewPanel) {
+
+        System.out.println("Track keys!");
+
+        final HIDInputTracker inputTracker = viewPanel.getHIDInputTracker();
+
+        final Avatar avatar = viewPanel.getAvatar();
+
+        final double actualAcceleration = millisecondsSinceLastFrame
+                * avatar.avatarAcceleration
+                * (1 + (avatar.getMovementSpeed() / 10));
+
+        if (inputTracker.isKeyPressed(KeyboardHelper.UP))
+            avatar.getMovementVector().z += actualAcceleration;
+
+        if (inputTracker.isKeyPressed(KeyboardHelper.DOWN))
+            avatar.getMovementVector().z -= actualAcceleration;
+
+        if (inputTracker.isKeyPressed(KeyboardHelper.RIGHT))
+            avatar.getMovementVector().x += actualAcceleration;
+
+        if (inputTracker.isKeyPressed(KeyboardHelper.LEFT))
+            avatar.getMovementVector().x -= actualAcceleration;
+
+        avatar.enforceSpeedLimit();
+    }
+}