Refactoring.
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Tue, 10 Jul 2018 15:40:00 +0000 (18:40 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Tue, 10 Jul 2018 15:40:00 +0000 (18:40 +0300)
src/main/java/eu/svjatoslav/sixth/e3d/geometry/TransformPipe.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/Avatar.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/View.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewUpdateListener.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/UserInputTracker.java
src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationTracker.java
src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/RenderAggregator.java
src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/ShapeCollection.java

index 0bf86a2..7df7991 100644 (file)
@@ -11,7 +11,7 @@ package eu.svjatoslav.sixth.e3d.geometry;
 
 public class TransformPipe {
 
-    Transform[] transforms = new Transform[100];
+    private Transform[] transforms = new Transform[100];
 
     private int transformsCount = 0;
 
index 4234593..6e4c5ec 100755 (executable)
@@ -11,6 +11,9 @@ package eu.svjatoslav.sixth.e3d.gui;
 
 import eu.svjatoslav.sixth.e3d.geometry.Point3D;
 
+import static java.lang.Math.cos;
+import static java.lang.Math.sin;
+
 public class Avatar implements ViewUpdateListener {
 
     public static final double SPEED_LIMIT = 30;
@@ -23,7 +26,7 @@ public class Avatar implements ViewUpdateListener {
      * are updated within the world, avatar orientation relative to the world is
      * taken into account.
      */
-    private final Point3D movementDirection = new Point3D();
+    private final Point3D movementVector = new Point3D();
     public double avatarAcceleration = 0.1;
     /**
      * Avatar location within the 3D world.
@@ -41,6 +44,11 @@ public class Avatar implements ViewUpdateListener {
      */
     private double orientationYZ;
 
+    /**
+     * Determines amount of friction user experiences every millisecond while moving around in space.
+     */
+    private static final double MILLISECOND_FRICTION = 1.005;
+
     public Avatar() {
     }
 
@@ -62,27 +70,27 @@ public class Avatar implements ViewUpdateListener {
     }
 
     @Override
-    public boolean beforeViewUpdate(final ViewContext viewContext,
-                                    final int millisecondsSinceLastFrame) {
+    public boolean beforeViewUpdate(final ViewContext viewContext, final int millisecondsSinceLastFrame) {
 
         final Point3D locationBeforeUpdate = new Point3D(location);
-        updateLocation(millisecondsSinceLastFrame);
-
-        final double distanceMoved = location
-                .getDistanceTo(locationBeforeUpdate);
+        translateAvatarLocation(millisecondsSinceLastFrame);
+        applyFrictionToUserMovement(millisecondsSinceLastFrame);
+        return isFrameRepaintNeeded(locationBeforeUpdate);
+    }
 
+    private boolean isFrameRepaintNeeded(Point3D locationBeforeUpdate) {
+        final double distanceMoved = location.getDistanceTo(locationBeforeUpdate);
         return distanceMoved > 0.03;
-
     }
 
     public void enforceSpeedLimit() {
-        final double currentSpeed = movementDirection
+        final double currentSpeed = movementVector
                 .getDistanceTo(Point3D.ZERO);
 
         if (currentSpeed <= SPEED_LIMIT)
             return;
 
-        movementDirection.scaleDown(currentSpeed / SPEED_LIMIT);
+        movementVector.scaleDown(currentSpeed / SPEED_LIMIT);
     }
 
     public double getAngleXZ() {
@@ -109,49 +117,48 @@ public class Avatar implements ViewUpdateListener {
         this.location = location;
     }
 
-    public Point3D getMovementDirection() {
-        return movementDirection;
+    public Point3D getMovementVector() {
+        return movementVector;
     }
 
     public double getMovementSpeed() {
-        return movementDirection.getDistanceTo(Point3D.ZERO);
+        return movementVector.getDistanceTo(Point3D.ZERO);
+    }
+
+    private void applyFrictionToUserMovement(int millisecondsPassedSinceLastFrame) {
+        for (int i = 0; i < millisecondsPassedSinceLastFrame; i++)
+            applyMillisecondFrictionToUserMovementVector();
+    }
+
+    private void applyMillisecondFrictionToUserMovementVector() {
+        getMovementVector().x /= MILLISECOND_FRICTION;
+        getMovementVector().y /= MILLISECOND_FRICTION;
+        getMovementVector().z /= MILLISECOND_FRICTION;
     }
 
     /**
-     * Update camera location based on current speed
+     * Translate coordinates based on avatar movement vector and avatar orientation in the world.
+     *
+     * @param millisecondsPassedSinceLastFrame We want avatar movement to be independent of framerate.
+     *                                         Therefore we take frame rendering time into account when translating
+     *                                         avatar between consecutive frames.
      */
-    public void updateLocation(final int millisecondsPassedSinceLastFrame) {
-
-        // translate user coordinates based on avatar movement speed, and avatar
-        // orientation in the world
-        {
-            location.x -= (float) Math.sin(getAngleXZ())
-                    * getMovementDirection().z * SPEED_MULTIPLIER
-                    * millisecondsPassedSinceLastFrame;
-            location.z += (float) Math.cos(getAngleXZ())
-                    * getMovementDirection().z * SPEED_MULTIPLIER
-                    * millisecondsPassedSinceLastFrame;
-
-            location.x += (float) Math.cos(getAngleXZ())
-                    * getMovementDirection().x * SPEED_MULTIPLIER
-                    * millisecondsPassedSinceLastFrame;
-            location.z += (float) Math.sin(getAngleXZ())
-                    * getMovementDirection().x * SPEED_MULTIPLIER
-                    * millisecondsPassedSinceLastFrame;
-
-            location.y += getMovementDirection().y * SPEED_MULTIPLIER
-                    * millisecondsPassedSinceLastFrame;
-        }
-
-        final double millisecondFriction = 1.005;
-        // apply friction to progressively slow movement
-        for (int i = 0; i < millisecondsPassedSinceLastFrame; i++) {
-            getMovementDirection().x = getMovementDirection().x
-                    / millisecondFriction;
-            getMovementDirection().y = getMovementDirection().y
-                    / millisecondFriction;
-            getMovementDirection().z = getMovementDirection().z
-                    / millisecondFriction;
-        }
+    private void translateAvatarLocation(int millisecondsPassedSinceLastFrame) {
+        location.x -= (float) sin(getAngleXZ())
+                * getMovementVector().z * SPEED_MULTIPLIER
+                * millisecondsPassedSinceLastFrame;
+        location.z += (float) cos(getAngleXZ())
+                * getMovementVector().z * SPEED_MULTIPLIER
+                * millisecondsPassedSinceLastFrame;
+
+        location.x += (float) cos(getAngleXZ())
+                * getMovementVector().x * SPEED_MULTIPLIER
+                * millisecondsPassedSinceLastFrame;
+        location.z += (float) sin(getAngleXZ())
+                * getMovementVector().x * SPEED_MULTIPLIER
+                * millisecondsPassedSinceLastFrame;
+
+        location.y += getMovementVector().y * SPEED_MULTIPLIER
+                * millisecondsPassedSinceLastFrame;
     }
 }
index bd60473..6f1b474 100755 (executable)
@@ -235,12 +235,12 @@ public class View extends JPanel implements ComponentListener {
         lastUpdateMillis = currentTime;
 
         // notify update listeners
-        boolean rerenderView = false;
+        boolean reRenderFrame = false;
 
         for (final ViewUpdateListener listener : viewUpdateListeners)
             if (listener.beforeViewUpdate(context,
                     millisecondsPassedSinceLastUpdate))
-                rerenderView = true;
+                reRenderFrame = true;
 
         // abort rendering if window size is invalid
         if ((getWidth() <= 0) || (getHeight() <= 0))
@@ -248,10 +248,10 @@ public class View extends JPanel implements ComponentListener {
 
         if (repaintDuringNextViewUpdate) {
             repaintDuringNextViewUpdate = false;
-            rerenderView = true;
+            reRenderFrame = true;
         }
 
-        if (rerenderView) {
+        if (reRenderFrame) {
             renderFrame();
             handleDetectedComponentMouseEvents();
         }
index 00f1faf..41a51f9 100644 (file)
@@ -12,10 +12,11 @@ package eu.svjatoslav.sixth.e3d.gui;
 public interface ViewUpdateListener {
 
     /**
-     * @return <code>true</code> if underlying view shall be re-rendered. If at
-     * least one of the view update listeners returns <code>true</code>,
-     * view is re-rendered.
+     * Notifies that it is about time to render next frame. Update listener can determine if frame repaint is actually
+     * needed from its perspective. Frame will be rendered if at least one listener says yes.
+     *
+     * @return <code>true</code> if underlying view shall be re-rendered. If at least one of the view update listeners
+     * returns <code>true</code>, view is re-rendered.
      */
-    boolean beforeViewUpdate(ViewContext viewContext,
-                             final int millisecondsSinceLastFrame);
+    boolean beforeViewUpdate(ViewContext viewContext, final int millisecondsSinceLastFrame);
 }
index 8e02ddf..dedfd78 100755 (executable)
@@ -229,7 +229,7 @@ public class UserInputTracker
         // track mouse wheel movements
         final double actualAcceleration = 50 * avatar.avatarAcceleration * (1 + (avatar.getMovementSpeed() / 10));
 
-        avatar.getMovementDirection().y += (wheelMovedDirection * actualAcceleration);
+        avatar.getMovementVector().y += (wheelMovedDirection * actualAcceleration);
         avatar.enforceSpeedLimit();
 
         // check if view shall be repainted
index 62f5586..59066a8 100644 (file)
@@ -56,16 +56,16 @@ public class WorldNavigationTracker implements UserInputHandler {
                 * (1 + (avatar.getMovementSpeed() / 10));
 
         if (inputTracker.isKeyPressed(KeyboardHelper.UP))
-            avatar.getMovementDirection().z += actualAcceleration;
+            avatar.getMovementVector().z += actualAcceleration;
 
         if (inputTracker.isKeyPressed(KeyboardHelper.DOWN))
-            avatar.getMovementDirection().z -= actualAcceleration;
+            avatar.getMovementVector().z -= actualAcceleration;
 
         if (inputTracker.isKeyPressed(KeyboardHelper.RIGHT))
-            avatar.getMovementDirection().x += actualAcceleration;
+            avatar.getMovementVector().x += actualAcceleration;
 
         if (inputTracker.isKeyPressed(KeyboardHelper.LEFT))
-            avatar.getMovementDirection().x -= actualAcceleration;
+            avatar.getMovementVector().x -= actualAcceleration;
 
         avatar.enforceSpeedLimit();
     }
index 049938c..3384351 100644 (file)
@@ -14,21 +14,16 @@ import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractCoordinateShape;
 
 import java.io.Serializable;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Comparator;
 
 public class RenderAggregator {
 
-    ArrayList<AbstractCoordinateShape> shapes = new ArrayList<>();
-    ShapesComparator comparator = new ShapesComparator();
+    private ArrayList<AbstractCoordinateShape> shapes = new ArrayList<>();
+    private ShapesZIndexComparator comparator = new ShapesZIndexComparator();
 
     public void paint(final RenderingContext renderBuffer) {
-
-        Collections.sort(shapes, comparator);
-
-        for (final AbstractCoordinateShape shape : shapes)
-            shape.paint(renderBuffer);
-
+        shapes.sort(comparator);
+        shapes.forEach(shape -> shape.paint(renderBuffer));
     }
 
     public void queueShapeForRendering(final AbstractCoordinateShape shape) {
@@ -39,7 +34,7 @@ public class RenderAggregator {
         shapes.clear();
     }
 
-    static class ShapesComparator implements Comparator<AbstractCoordinateShape>, Serializable {
+    static class ShapesZIndexComparator implements Comparator<AbstractCoordinateShape>, Serializable {
 
         @Override
         public int compare(final AbstractCoordinateShape o1, final AbstractCoordinateShape o2) {
index cbab6f4..b453f74 100755 (executable)
@@ -47,7 +47,7 @@ public class ShapeCollection {
         aggregator.reset();
         transformPipe.clear();
 
-        // translate scene according to avatar current location
+        // translate scene according to camera current location
         final Avatar avatar = viewContext.getAvatar();
 
         // rotate scene according to avatar looking direction