diff --git a/lucien/src/main/java/com/hellblazer/luciferase/lucien/animus/Rotor3f.java b/lucien/src/main/java/com/hellblazer/luciferase/lucien/animus/Rotor3f.java index 3281dfc..e064be7 100644 --- a/lucien/src/main/java/com/hellblazer/luciferase/lucien/animus/Rotor3f.java +++ b/lucien/src/main/java/com/hellblazer/luciferase/lucien/animus/Rotor3f.java @@ -78,15 +78,31 @@ Vector3f b() { } }; - private static final Vector3f POS_X = new Vector3f(1, 0, 0); - private static final Vector3f POS_Y = new Vector3f(0, 1, 0); - private static final Vector3f POS_Z = new Vector3f(0, 0, 1); + private static final float HALF_PI = (float) (Math.PI / 2); + private static final Vector3f POS_X = new Vector3f(1, 0, 0); + private static final Vector3f POS_Y = new Vector3f(0, 1, 0); + private static final Vector3f POS_Z = new Vector3f(0, 0, 1); + + public Rotor3f angle(float theta) { + return slerp(theta / 90); + } /** - * Spherical Linear Interpolation from axis A to axis B. + * Spherical Linear Interpolation around the axis by the supplied radians * - * @param t - the parameterization value - * @return the Rotor3f corresponding to point (t) in the interpolation from a() + * @param theta - the radians of rotation about the axis + * @return the Rotor3f corresponding to rotation in the interpolation from a() + * to b() + */ + public Rotor3f radians(float theta) { + return slerp(theta / HALF_PI); + } + + /** + * Spherical Linear Interpolation around the axis by the supplied angle + * + * @param theta - the angle of rotation about the axis + * @return the Rotor3f corresponding to rotation in the interpolation from a() * to b() */ public Rotor3f slerp(float t) { @@ -356,6 +372,11 @@ public Matrix4f toMatrix() { return result; } + @Override + public String toString() { + return String.format("Rotor3f [a=%s, xy=%s, yz=%s, zx=%s]", a, xy, yz, zx); + } + /** * Transform the vector using the receiver * diff --git a/portal/src/main/java/com/hellblazer/luciferase/portal/Animus.java b/portal/src/main/java/com/hellblazer/luciferase/portal/Animus.java deleted file mode 100644 index 5059c91..0000000 --- a/portal/src/main/java/com/hellblazer/luciferase/portal/Animus.java +++ /dev/null @@ -1,120 +0,0 @@ -/** - * Copyright (C) 2023 Hal Hildebrand. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU Affero General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more - * details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.hellblazer.luciferase.portal; - -import javax.vecmath.Vector3f; - -import com.hellblazer.luciferase.lucien.animus.Oriented; -import com.hellblazer.luciferase.lucien.animus.Rotor3f; - -import javafx.beans.Observable; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ObservableValue; -import javafx.scene.Node; -import javafx.scene.transform.Affine; -import javafx.scene.transform.Translate; - -/** - * Integrated control of position and orientation for a JavaFX node - * - * @author hal.hildebrand - */ -public class Animus { - - private final N animated; - private final ObjectProperty orientation = new SimpleObjectProperty<>(); - private final ObjectProperty position = new SimpleObjectProperty<>(); - private final Oriented tracking; - - public Animus(N animated) { - this(new Oriented(), animated); - } - - public Animus(Oriented tracking, N animated) { - this.animated = animated; - this.tracking = tracking; - updateTransforms(); - position.set(new Vector3f(tracking)); - orientation.set(new Rotor3f(tracking.orientation())); - position.addListener(p -> updatePosition(p)); - orientation.addListener(r -> updateOrientation(r)); - } - - /** - * @return the JavaFX Node animated by this Orientable - */ - public N getAnimated() { - return animated; - } - - /** - * @return the Property used to orient the animated Node - */ - public ObjectProperty getOrientation() { - return orientation; - } - - /** - * - * @return the Property used to position the animated Node - */ - public ObjectProperty getPosition() { - return position; - } - - /** - * Used to update the properties on state change - */ - protected void update() { - updateTransforms(); - position.set(new Vector3f(tracking)); - tracking.orientation().set(new Rotor3f(tracking.orientation())); - } - - protected void updateTransforms() { - final var t = animated.getTransforms(); - t.clear(); - t.addAll(translate(), transform()); - } - - private Affine transform() { - final var m = tracking.orientation().toMatrix(); - var t = new Affine(); - t.setToTransform(m.getM00(), m.getM10(), m.getM20(), m.getM30(), m.getM01(), m.getM11(), m.getM21(), m.getM31(), - m.getM02(), m.getM12(), m.getM22(), m.getM32()); - return t; - } - - private Translate translate() { - return new Translate(tracking.x, tracking.y, tracking.z); - } - - private void updateOrientation(Observable r) { - if (r instanceof ObservableValue o) { - tracking.orientation().set((Rotor3f) o.getValue()); - } - updateTransforms(); - } - - private void updatePosition(Observable p) { - if (p instanceof ObservableValue o) { - tracking.set((Vector3f) o.getValue()); - } - updateTransforms(); - } -} diff --git a/portal/src/main/java/com/hellblazer/luciferase/portal/MagicMirror.java b/portal/src/main/java/com/hellblazer/luciferase/portal/MagicMirror.java index 62d2462..b97078b 100644 --- a/portal/src/main/java/com/hellblazer/luciferase/portal/MagicMirror.java +++ b/portal/src/main/java/com/hellblazer/luciferase/portal/MagicMirror.java @@ -20,32 +20,32 @@ import static com.hellblazer.luciferase.lucien.animus.Rotor3f.PrincipalAxis.Y; import static com.hellblazer.luciferase.lucien.animus.Rotor3f.PrincipalAxis.Z; -import javax.vecmath.Point3f; -import javax.vecmath.Vector3f; - import com.hellblazer.luciferase.lucien.animus.Rotor3f; import com.hellblazer.luciferase.portal.CubicGrid.Neighborhood; +import com.hellblazer.luciferase.portal.mesh.explorer.Xform; import com.hellblazer.luciferase.portal.mesh.polyhedra.plato.Cube; import javafx.application.Application; import javafx.event.EventHandler; +import javafx.geometry.Point3D; import javafx.scene.Camera; import javafx.scene.DepthTest; import javafx.scene.Group; -import javafx.scene.Node; +import javafx.scene.PerspectiveCamera; import javafx.scene.Scene; import javafx.scene.SceneAntialiasing; import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseEvent; import javafx.scene.input.ScrollEvent; import javafx.scene.paint.Color; +import javafx.scene.transform.Rotate; +import javafx.scene.transform.Translate; import javafx.stage.Stage; /** * @author hal.hildebrand */ public abstract class MagicMirror extends Application { - public static class MouseHandler { protected double mouseDeltaX; protected double mouseDeltaY; @@ -53,39 +53,71 @@ public static class MouseHandler { protected double mouseOldY; protected double mousePosX; protected double mousePosY; + protected float rx; + protected float ry; } - public static final float CUBE_EDGE_LENGTH = (float) (Math.sqrt(2) / 2); - public static final float TET_EDGE_LENGTH = 1; - protected static final double AXIS_LENGTH = 250.0; - protected static final double CONTROL_MULTIPLIER = 0.1; - protected static final double MOUSE_SPEED = 0.1; - protected static final double ROTATION_SPEED = 2.0; - protected static final double SHIFT_MULTIPLIER = 10.0; - protected static final double TRACK_SPEED = 0.3; + public static final float CUBE_EDGE_LENGTH = (float) (Math.sqrt(2) / 2); + + public static final float TET_EDGE_LENGTH = 1; + protected static final float AXIS_LENGTH = 250.0f; + protected static final float CAMERA_FAR_CLIP = 10000.0f; + protected static final float CAMERA_INITIAL_DISTANCE = -450f; + protected static final float CAMERA_INITIAL_X_ANGLE = 70.0f; + protected static final float CAMERA_INITIAL_Y_ANGLE = 320.0f; + protected static final float CAMERA_NEAR_CLIP = 0.1f; + protected static final float CONTROL_MULTIPLIER = 0.1f; + protected static final float MOUSE_SPEED = 0.1f; + protected static final float ROTATION_SPEED = 2.0f; + protected static final float SHIFT_MULTIPLIER = 10.0f; + protected static final float TRACK_SPEED = 0.3f; + + public static void lookAt(Point3D cameraPosition, Point3D lookAtPos, Camera cam) { + // Create direction vector + Point3D camDirection = lookAtPos.subtract(cameraPosition.getX(), cameraPosition.getY(), cameraPosition.getZ()); + camDirection = camDirection.normalize(); + double xRotation = Math.toDegrees(Math.asin(-camDirection.getY())); + double yRotation = Math.toDegrees(Math.atan2(camDirection.getX(), camDirection.getZ())); + Rotate rx = new Rotate(xRotation, cameraPosition.getX(), cameraPosition.getY(), cameraPosition.getZ(), + Rotate.X_AXIS); + Rotate ry = new Rotate(yRotation, cameraPosition.getX(), cameraPosition.getY(), cameraPosition.getZ(), + Rotate.Y_AXIS); + cam.getTransforms() + .addAll(ry, rx, new Translate(cameraPosition.getX(), cameraPosition.getY(), cameraPosition.getZ())); + } public static void main(String[] args) { launch(args); } - protected final Group axisGroup = new Group(); - protected Portal portal; - protected final Group root = new Group(); - protected final Xform transformingGroup = new Xform(); - protected final Xform world = new Xform(); + protected final Group axisGroup = new Group(); + protected final PerspectiveCamera camera; + protected final OrientedGroup cameraTransform; + protected final Group root = new Group(); + protected final Xform transformingGroup = new Xform(); + protected final Xform world = new Xform(); public MagicMirror() { super(); + + var t = new OrientedTxfm(); + t.next(new OrientedTxfm()).next(new OrientedTxfm()).setRotate(0, 0, 180.0f); + t.setRotate(CAMERA_INITIAL_X_ANGLE, CAMERA_INITIAL_Y_ANGLE, 0); + + cameraTransform = new OrientedGroup(t); + camera = new PerspectiveCamera(true); + cameraTransform.getChildren().add(camera); } @Override public void start(Stage primaryStage) throws Exception { root.getChildren().add(world); root.setDepthTest(DepthTest.ENABLE); - portal = portal(); - - world.getChildren().addAll(portal.getAvatar().getAnimated(), portal.getCamera().getAnimated()); + root.getChildren().add(cameraTransform); + camera.setNearClip(CAMERA_NEAR_CLIP); + camera.setFarClip(CAMERA_FAR_CLIP); + camera.setTranslateZ(CAMERA_INITIAL_DISTANCE / 4); buildAxes(); Scene scene = new Scene(root, 1024, 768, true, SceneAntialiasing.BALANCED); @@ -97,8 +129,7 @@ public void start(Stage primaryStage) throws Exception { primaryStage.setScene(scene); primaryStage.show(); - portal.setCamera(scene); - resetCameraDefault(); + scene.setCamera(camera); // Attach a scroll listener primaryStage.addEventHandler(ScrollEvent.SCROLL, event -> { @@ -110,16 +141,12 @@ public void start(Stage primaryStage) throws Exception { if (event.isShiftDown()) { modifier = 100.0f; } - var position = portal.getCamera().getPosition(); - - final var p = position.get(); - p.z = (float) (p.z + event.getDeltaY() * modifierFactor * modifier); - position.set(p); + double z = camera.getTranslateZ(); + double newZ = z + event.getDeltaY() * modifierFactor * modifier; + camera.setTranslateZ(newZ); }); } - abstract protected Animus animus(); - protected void buildAxes() { final var cubic = new CubicGrid(Neighborhood.EIGHT, new Cube(CUBE_EDGE_LENGTH), 1); cubic.addAxes(axisGroup, 0.1, 0.2, 0.008, 20); @@ -127,8 +154,6 @@ protected void buildAxes() { world.getChildren().addAll(axisGroup); } - abstract protected Animus camera(); - protected void handleKeyboard(Scene scene) { scene.setOnKeyPressed(new EventHandler() { @@ -136,7 +161,7 @@ protected void handleKeyboard(Scene scene) { public void handle(KeyEvent event) { switch (event.getCode()) { case Z: - resetCameraDefault(); + cameraTransform.getTransform().reset(); break; case X: axisGroup.setVisible(!axisGroup.isVisible()); @@ -153,8 +178,6 @@ public void handle(KeyEvent event) { protected MouseHandler handleMouse(Scene scene) { var h = new MouseHandler(); - final var position = portal.getCamera().getPosition(); - final var orientation = portal.getCamera().getOrientation(); scene.setOnMousePressed(new EventHandler() { @Override @@ -183,33 +206,24 @@ public void handle(MouseEvent me) { if (me.isShiftDown()) { modifier = SHIFT_MULTIPLIER; } - + var t = cameraTransform.getTransform(); if (me.isMiddleButtonDown() || (me.isPrimaryButtonDown() && me.isSecondaryButtonDown())) { - var p = new Vector3f(position.get()); - p.add(new Point3f((float) (h.mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED), - (float) (h.mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED), 0f)); - position.set(p); + t.t.setX((float) (t.t.getX() + h.mouseDeltaX * MOUSE_SPEED * modifier * TRACK_SPEED)); + t.next.t.setY(t.next.t.getY() + h.mouseDeltaY * MOUSE_SPEED * modifier * TRACK_SPEED); } else if (me.isPrimaryButtonDown()) { - var o = new Rotor3f(orientation.get()); - o.combine(X.slerp((float) (-h.mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED))) - .combine(Y.slerp((float) (h.mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED))); - orientation.set(o); + h.ry = (float) (h.ry - h.mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED); + h.rx = (float) (h.rx + h.mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED); + t.setRotate(h.rx, h.ry, 0); } else if (me.isSecondaryButtonDown()) { - var p = new Vector3f(position.get()); - p.z = (float) (p.z + h.mouseDeltaX * MOUSE_SPEED * modifier); - position.set(p); + double z = camera.getTranslateZ(); + double newZ = z + h.mouseDeltaX * MOUSE_SPEED * modifier; + camera.setTranslateZ(newZ); } } }); return h; } - protected Portal portal() { - return new Portal(animus(), camera()); - } - - abstract protected void resetCameraDefault(); - protected Rotor3f rotation(KeyEvent event, float t) { return switch (event.getCode()) { case A -> X.slerp(t); diff --git a/portal/src/main/java/com/hellblazer/luciferase/portal/Portal.java b/portal/src/main/java/com/hellblazer/luciferase/portal/OrientedGroup.java similarity index 56% rename from portal/src/main/java/com/hellblazer/luciferase/portal/Portal.java rename to portal/src/main/java/com/hellblazer/luciferase/portal/OrientedGroup.java index 506e0f7..da3c706 100644 --- a/portal/src/main/java/com/hellblazer/luciferase/portal/Portal.java +++ b/portal/src/main/java/com/hellblazer/luciferase/portal/OrientedGroup.java @@ -16,35 +16,26 @@ */ package com.hellblazer.luciferase.portal; -import javafx.scene.Camera; -import javafx.scene.Node; -import javafx.scene.Scene; +import javafx.scene.Group; /** + * A group that encapsulates a chain of oriented transforms + * * @author hal.hildebrand */ -public class Portal { - private final Animus avatar; - private final Animus camera; +public class OrientedGroup extends Group { + private final OrientedTxfm txfm; - public Portal(Animus avatar, Animus camera) { - this.avatar = avatar; - this.camera = camera; + public OrientedGroup(OrientedTxfm txfm) { + this.txfm = txfm; + apply(); } - public Portal(Node avatar, Camera camera) { - this(new Animus<>(avatar), new Animus<>(camera)); + public void apply() { + txfm.accept(this); } - public Animus getAvatar() { - return avatar; - } - - public Animus getCamera() { - return camera; - } - - public void setCamera(Scene scene) { - scene.setCamera(camera.getAnimated()); + public OrientedTxfm getTransform() { + return txfm; } } diff --git a/portal/src/main/java/com/hellblazer/luciferase/portal/OrientedTxfm.java b/portal/src/main/java/com/hellblazer/luciferase/portal/OrientedTxfm.java new file mode 100644 index 0000000..5f78424 --- /dev/null +++ b/portal/src/main/java/com/hellblazer/luciferase/portal/OrientedTxfm.java @@ -0,0 +1,184 @@ +/** + * Copyright (C) 2023 Hal Hildebrand. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.hellblazer.luciferase.portal; + +import static com.hellblazer.luciferase.lucien.animus.Rotor3f.PrincipalAxis.X; +import static com.hellblazer.luciferase.lucien.animus.Rotor3f.PrincipalAxis.Y; +import static com.hellblazer.luciferase.lucien.animus.Rotor3f.PrincipalAxis.Z; + +import java.util.function.Consumer; + +import javax.vecmath.Tuple3f; + +import com.hellblazer.luciferase.lucien.animus.Rotor3f; + +import javafx.scene.Node; +import javafx.scene.transform.Affine; +import javafx.scene.transform.Scale; +import javafx.scene.transform.Translate; + +/** + * Composable transform. This is a Translate, followed by the transform to the + * orientation and then finally the scaling. This class is designed to be + * chained together to perform complex transformations and then to apply these + * transformations to any given Node. + * + * @author hal.hildebrand + */ +public class OrientedTxfm implements Consumer { + OrientedTxfm next; + final Rotor3f orientation = new Rotor3f(); + final Scale s = new Scale(); + final Translate t = new Translate(); + + @Override + public void accept(Node node) { + final var transforms = node.getTransforms(); + transforms.clear(); + var current = this; + while (current != null) { + transforms.addAll(current.t, current.transform(), current.s); + current = current.next; + } + } + + /** + * Set the next txfm of the receiver, return the txfm + * + * @param txfm + * @return the passed txfm + */ + public OrientedTxfm next(OrientedTxfm txfm) { + next = txfm; + return txfm; + } + + /** + * Reset to zero'd state + */ + public void reset() { + t.setX(0.0); + t.setY(0.0); + t.setZ(0.0); + orientation.set(new Rotor3f()); + s.setX(1.0); + s.setY(1.0); + s.setZ(1.0); + } + + /** + * Reset translate and scale + */ + public void resetTS() { + t.setX(0.0); + t.setY(0.0); + t.setZ(0.0); + s.setX(1.0); + s.setY(1.0); + s.setZ(1.0); + } + + public void setOrientation(Rotor3f orientation) { + this.orientation.set(orientation); + } + + /** + * set the orientation to the supplied angles rotation around the primary axis + * + * @param x + * @param y + * @param z + */ + public void setRotate(float x, float y, float z) { + orientation.set(X.angle(-x).combine(Y.angle(-y)).combine(Z.angle(z))); + } + + /** + * scale everything + * + * @param scaleFactor + */ + public void setScale(double scaleFactor) { + s.setX(scaleFactor); + s.setY(scaleFactor); + s.setZ(scaleFactor); + } + + /** + * Scale by component + */ + public void setScale(double x, double y, double z) { + s.setX(x); + s.setY(y); + s.setZ(z); + } + + public void setScaleX(double x) { + s.setX(x); + } + + public void setScaleY(double y) { + s.setY(y); + } + + public void setScaleZ(double z) { + s.setZ(z); + } + + public void setTranslate(double x, double y) { + t.setX(x); + t.setY(y); + } + + public void setTranslate(double x, double y, double z) { + t.setX(x); + t.setY(y); + t.setZ(z); + } + + public void setTranslate(Tuple3f p) { + t.setX(p.x); + t.setY(p.y); + t.setZ(p.z); + } + + public void setTranslateX(double x) { + t.setX(x); + } + + public void setTranslateY(double y) { + t.setY(y); + } + + public void setTranslateZ(double z) { + t.setZ(z); + } + + @Override + public String toString() { + return "OrientedTxfm[t = (" + t.getX() + ", " + t.getY() + ", " + t.getZ() + ") " + "r = (" + orientation + + ") " + "s = (" + s.getX() + ", " + s.getY() + ", " + s.getZ() + ")]"; + } + + private Affine transform() { + final var m = orientation.toMatrix(); + var t = new Affine(); + t.setToTransform(m.getM00(), m.getM10(), m.getM20(), m.getM30(), m.getM01(), m.getM11(), m.getM21(), m.getM31(), + m.getM02(), m.getM12(), m.getM22(), m.getM32()); + return t; + } +} diff --git a/portal/src/main/java/com/hellblazer/luciferase/portal/Scaled.java b/portal/src/main/java/com/hellblazer/luciferase/portal/Scaled.java deleted file mode 100644 index cef2ec7..0000000 --- a/portal/src/main/java/com/hellblazer/luciferase/portal/Scaled.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (C) 2023 Hal Hildebrand. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU Affero General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more - * details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.hellblazer.luciferase.portal; - -import com.hellblazer.luciferase.lucien.animus.Oriented; - -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.scene.Node; -import javafx.scene.transform.Scale; - -/** - * Scaled Animus - * - * @author hal.hildebrand - */ -public class Scaled extends Animus { - private final ObjectProperty scale; - - public Scaled(N animated) { - this(new Oriented(), animated); - } - - public Scaled(Oriented tracking, N animated) { - this(tracking, animated, new Scale()); - } - - public Scaled(Oriented tracking, N animated, Scale scale) { - super(tracking, animated); - this.scale = new SimpleObjectProperty<>(scale); - } - - @Override - protected void updateTransforms() { - super.updateTransforms(); - getAnimated().getTransforms().add(scale.getValue()); - } -} diff --git a/portal/src/main/java/com/hellblazer/luciferase/portal/mesh/explorer/Abstract3DApp.java b/portal/src/main/java/com/hellblazer/luciferase/portal/mesh/explorer/Abstract3DApp.java index b5e4a6d..62cfccd 100644 --- a/portal/src/main/java/com/hellblazer/luciferase/portal/mesh/explorer/Abstract3DApp.java +++ b/portal/src/main/java/com/hellblazer/luciferase/portal/mesh/explorer/Abstract3DApp.java @@ -18,7 +18,6 @@ import com.hellblazer.luciferase.portal.CubicGrid; import com.hellblazer.luciferase.portal.CubicGrid.Neighborhood; -import com.hellblazer.luciferase.portal.Xform; import com.hellblazer.luciferase.portal.mesh.polyhedra.plato.Cube; import javafx.application.Application; @@ -39,17 +38,17 @@ */ public abstract class Abstract3DApp extends Application { - public static final float CUBE_EDGE_LENGTH = (float) (Math.sqrt(2) / 2); - protected static final double AXIS_LENGTH = 250.0; - protected static final double CAMERA_FAR_CLIP = 10000.0; - protected static final double CAMERA_INITIAL_DISTANCE = -450; - protected static final double CAMERA_INITIAL_X_ANGLE = 70.0; - protected static final double CAMERA_INITIAL_Y_ANGLE = 320.0; - protected static final double CAMERA_NEAR_CLIP = 0.1; - protected static final double CONTROL_MULTIPLIER = 0.1; - protected static final double MOUSE_SPEED = 0.1; - protected static final double ROTATION_SPEED = 2.0; - protected static final double SHIFT_MULTIPLIER = 10.0; + public static final float CUBE_EDGE_LENGTH = (float) (Math.sqrt(2) / 2); + protected static final float AXIS_LENGTH = 250.0f; + protected static final float CAMERA_FAR_CLIP = 10000.0f; + protected static final float CAMERA_INITIAL_DISTANCE = -450; + protected static final float CAMERA_INITIAL_X_ANGLE = 70.0f; + protected static final float CAMERA_INITIAL_Y_ANGLE = 320.0f; + protected static final float CAMERA_NEAR_CLIP = 0.1f; + protected static final float CONTROL_MULTIPLIER = 0.1f; + protected static final float MOUSE_SPEED = 0.1f; + protected static final float ROTATION_SPEED = 2.0f; + protected static final float SHIFT_MULTIPLIER = 10.0f; protected static final double TRACK_SPEED = 0.3; protected final Xform axisGroup = new Xform(); diff --git a/portal/src/main/java/com/hellblazer/luciferase/portal/Xform.java b/portal/src/main/java/com/hellblazer/luciferase/portal/mesh/explorer/Xform.java similarity index 95% rename from portal/src/main/java/com/hellblazer/luciferase/portal/Xform.java rename to portal/src/main/java/com/hellblazer/luciferase/portal/mesh/explorer/Xform.java index e07db62..4ac3c69 100644 --- a/portal/src/main/java/com/hellblazer/luciferase/portal/Xform.java +++ b/portal/src/main/java/com/hellblazer/luciferase/portal/mesh/explorer/Xform.java @@ -30,7 +30,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.hellblazer.luciferase.portal; +package com.hellblazer.luciferase.portal.mesh.explorer; import javafx.scene.Group; import javafx.scene.transform.Rotate; diff --git a/portal/src/test/java/com/hellblazer/luciferase/portal/TestPortal.java b/portal/src/test/java/com/hellblazer/luciferase/portal/TestPortal.java index 91de6a6..14ad1e8 100644 --- a/portal/src/test/java/com/hellblazer/luciferase/portal/TestPortal.java +++ b/portal/src/test/java/com/hellblazer/luciferase/portal/TestPortal.java @@ -18,7 +18,7 @@ import java.util.Set; -import javax.vecmath.Vector3f; +import javax.vecmath.Point3f; import com.hellblazer.luciferase.portal.CubicGrid.Neighborhood; import com.hellblazer.luciferase.portal.mesh.Edge; @@ -28,10 +28,8 @@ import com.hellblazer.luciferase.portal.mesh.polyhedra.archimedes.Cuboctahedron; import com.hellblazer.luciferase.portal.mesh.polyhedra.plato.Cube; -import javafx.scene.Camera; import javafx.scene.Group; import javafx.scene.Node; -import javafx.scene.PerspectiveCamera; import javafx.scene.paint.Material; import javafx.scene.shape.CullFace; import javafx.scene.shape.MeshView; @@ -51,12 +49,6 @@ public static void main(String[] argv) { } } - protected static final float CAMERA_FAR_CLIP = 10000.0f; - protected static final float CAMERA_INITIAL_DISTANCE = -450f; - protected static final float CAMERA_INITIAL_X_ANGLE = 70.0f; - protected static final float CAMERA_INITIAL_Y_ANGLE = 320.0f; - protected static final float CAMERA_NEAR_CLIP = 0.1f; - public static void add(final Polyhedron polyhedron, Group view) { MeshView v = new MeshView(polyhedron.toTriangleMesh().constructMesh()); v.setMaterial(Colors.cyanMaterial); @@ -85,61 +77,19 @@ public static void main(String[] args) { launch(args); } - protected final Xform cameraXform = new Xform(); - - protected final Xform cameraXform2 = new Xform(); + protected Node content() { + OrientedTxfm txfm = new OrientedTxfm(); + txfm.setTranslate(new Point3f(0, 0, 2)); + txfm.setRotate(45, 45, -45); + var view = new OrientedGroup(txfm); - protected final Xform cameraXform3 = new Xform(); - - @Override - protected Animus animus() { - var view = new Group(); final var cubic = new CubicGrid(Neighborhood.EIGHT, new Cube(CUBE_EDGE_LENGTH), 1); cubic.addAxes(view, 0.1, 0.2, 0.008, 20); Polyhedron polyhedron = new Cuboctahedron(TET_EDGE_LENGTH); var dual = polyhedron.dual(); var dualEdges = dual.getEdges(); - addEdges(dualEdges, Colors.redMaterial, view); - var animus = new Animus(view); - - var p = new Vector3f(); - p.z = p.z + 2; - animus.getPosition().set(p); -// animus.getOrientation().set(PrincipalAxis.Y.slerp(-0.5f).combine(PrincipalAxis.Z.slerp(0.5f))); - - return animus; - } - - @Override - protected Animus camera() { - final var camera = new PerspectiveCamera(true); - final Animus animus = new Animus<>(camera); - return animus; - } - - @Override - protected void resetCameraDefault() { - final var camera = portal.getCamera().getAnimated(); - root.getChildren().add(cameraXform); - cameraXform.getChildren().add(cameraXform2); - cameraXform2.getChildren().add(cameraXform3); - cameraXform3.getChildren().add(camera); - cameraXform3.setRotateZ(180.0); - - camera.setNearClip(CAMERA_NEAR_CLIP); - camera.setFarClip(CAMERA_FAR_CLIP); - camera.setTranslateZ(CAMERA_INITIAL_DISTANCE / 4); - cameraXform.ry.setAngle(CAMERA_INITIAL_Y_ANGLE); - cameraXform.rx.setAngle(CAMERA_INITIAL_X_ANGLE); - -// final var camera = portal.getCamera(); -// root.getChildren().add(camera.getAnimated()); -// camera.getAnimated().setNearClip(CAMERA_NEAR_CLIP); -// camera.getAnimated().setFarClip(CAMERA_FAR_CLIP); -// -// camera.getPosition().set(new Vector3f(0, 0, -CAMERA_INITIAL_DISTANCE / 4)); -// camera.getOrientation().set(PrincipalAxis.Y.slerp(2f)); + return view; } @Override diff --git a/portal/src/test/java/com/hellblazer/luciferase/portal/Viewer.java b/portal/src/test/java/com/hellblazer/luciferase/portal/Viewer.java index 1dc3667..9b85e23 100644 --- a/portal/src/test/java/com/hellblazer/luciferase/portal/Viewer.java +++ b/portal/src/test/java/com/hellblazer/luciferase/portal/Viewer.java @@ -19,6 +19,7 @@ import static com.hellblazer.luciferase.portal.MagicMirror.TET_EDGE_LENGTH; import static com.hellblazer.luciferase.portal.TestPortal.addEdges; +import javax.vecmath.Point3f; import javax.vecmath.Vector3f; import com.hellblazer.luciferase.portal.CubicGrid.Neighborhood; @@ -50,11 +51,11 @@ public static void main(String[] args) { launch(args); } - private Animus animus; - private Animus fauxCamera; - protected Node animus() { - var view = new Group(); + OrientedTxfm txfm = new OrientedTxfm(); + txfm.setTranslate(new Point3f(0, 0, 2)); + txfm.setRotate(45, 45, -45); + var view = new OrientedGroup(txfm); final var cubic = new CubicGrid(Neighborhood.EIGHT, new Cube(CUBE_EDGE_LENGTH), 1); cubic.addAxes(view, 0.1, 0.2, 0.008, 20); Polyhedron polyhedron = new Cuboctahedron(TET_EDGE_LENGTH); @@ -62,14 +63,7 @@ protected Node animus() { var dualEdges = dual.getEdges(); addEdges(dualEdges, Colors.redMaterial, view); - animus = new Animus(view); - - var p = new Vector3f(); - p.z = p.z + 2; - animus.getPosition().set(p); -// animus.getOrientation().set(PrincipalAxis.Y.slerp(-0.5f).combine(PrincipalAxis.Z.slerp(0.5f))); - - return animus.getAnimated(); + return view; } @Override @@ -77,14 +71,17 @@ protected Group build() { var g = new Group(); g.getChildren().add(animus()); final var cubic = new CubicGrid(Neighborhood.EIGHT, new Cube(CUBE_EDGE_LENGTH), 1); -// cubic.addAxes(g, 0.1, 0.2, 0.008, 20); - fauxCamera = new Animus<>(new Group()); - cubic.addAxes(fauxCamera.getAnimated(), 0.1, 0.2, 0.008, 20); - g.getChildren().add(fauxCamera.getAnimated()); + var fauxCamera = new Group(); + cubic.addAxes(fauxCamera, 0.1, 0.2, 0.008, 20); + g.getChildren().add(fauxCamera); + + var t = new OrientedTxfm(); + t.next(new OrientedTxfm()).next(new OrientedTxfm()).setRotate(0, 0, 180.0f); + t.setRotate(CAMERA_INITIAL_X_ANGLE, CAMERA_INITIAL_Y_ANGLE, 0); + t.setTranslate(new Vector3f(0, 0, 20)); - fauxCamera.getPosition().set(new Vector3f(0, 0, -20)); -// fauxCamera.getOrientation().set(PrincipalAxis.Y.slerp(2f)); + t.accept(fauxCamera); return g; }