From: Svjatoslav Agejenko Date: Sun, 22 Jul 2018 20:36:06 +0000 (+0300) Subject: Code refactoring. X-Git-Tag: sixth-3d-1.2~30 X-Git-Url: http://www2.svjatoslav.eu/gitweb/?p=sixth-3d.git;a=commitdiff_plain;h=70ee733b25c56bed539b89ff5507ae0af842d68a Code refactoring. --- diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/Avatar.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/Avatar.java index 52d78b2..852dc97 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/Avatar.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/Avatar.java @@ -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; 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 75dbbf4..70350e0 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/GuiComponent.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/GuiComponent.java @@ -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 diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewFrame.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewFrame.java index 874673f..1383c72 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewFrame.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewFrame.java @@ -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 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 6fda153..b23bf5b 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewPanel.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewPanel.java @@ -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 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 index 0000000..6015ee7 --- /dev/null +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/HIDInputTracker.java @@ -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 { + + /** + *
+     * 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.
+     * 
+ */ + private final Map pressedKeysToPressedTimeMap = new HashMap<>(); + private final List detectedMouseClicks = new ArrayList<>(); + private final List 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 true if view needs to be repainted. + */ + private boolean handleKeyboardEvents() { + final UserInputHandler currentFocusOwner = viewPanel.getKeyboardFocusStack().getCurrentFocusOwner(); + ArrayList unprocessedKeyboardEvents = getUnprocessedKeyboardEvents(); + + return currentFocusOwner != null + && forwardKeyboardEventsToFocusOwner(currentFocusOwner, unprocessedKeyboardEvents); + } + + private ArrayList getUnprocessedKeyboardEvents() { + synchronized (detectedKeyEvents) { + ArrayList result = new ArrayList<>(detectedKeyEvents); + detectedKeyEvents.clear(); + return result; + } + } + + /** + * @return true if view update is needed. + */ + private boolean forwardKeyboardEventsToFocusOwner( + UserInputHandler currentFocusOwner, ArrayList 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 true 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 true 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 true 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 index 0000000..4ee7ed8 --- /dev/null +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusStack.java @@ -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 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 index 65e9374..0000000 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/KeyboardFocusTracker.java +++ /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 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 index 3060691..0000000 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/UserInputTracker.java +++ /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 { - - /** - *
-     * 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.
-     * 
- */ - private final Map pressedKeysToPressedTimeMap = new HashMap<>(); - private final List detectedMouseClicks = new ArrayList<>(); - private final List 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 true if view needs to be repainted. - */ - private boolean handleKeyboardEvents() { - final UserInputHandler currentFocusOwner = viewPanel.getKeyboardFocusTracker().getCurrentFocusOwner(); - ArrayList unprocessedKeyboardEvents = getUnprocessedKeyboardEvents(); - - return currentFocusOwner == null ? false : - forwardKeyboardEventsToFocusOwner(currentFocusOwner, unprocessedKeyboardEvents); - } - - private ArrayList getUnprocessedKeyboardEvents() { - synchronized (detectedKeyEvents) { - ArrayList result = new ArrayList<>(detectedKeyEvents); - detectedKeyEvents.clear(); - return result; - } - } - - /** - * @return true if view update is needed. - */ - private boolean forwardKeyboardEventsToFocusOwner( - UserInputHandler currentFocusOwner, ArrayList 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 true 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 true 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 true 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 index 28d485c..0000000 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationTracker.java +++ /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 index 0000000..d80924c --- /dev/null +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationUserInputTracker.java @@ -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(); + } +}