diff --git a/racevisionGame/pom.xml b/racevisionGame/pom.xml index 41157414..4a3c65a4 100644 --- a/racevisionGame/pom.xml +++ b/racevisionGame/pom.xml @@ -46,14 +46,17 @@ 15.0 - - org.geotools gt-referencing 9.0 + + JavaInteractiveMesh + STLImporter + 0.7 + @@ -72,7 +75,11 @@ http://download.osgeo.org/webdav/geotools/ - + + interactivemesh + Interactive Mesh + http://umbrasheep.com:8888/repository/internal/ + diff --git a/racevisionGame/src/main/java/visualiser/Controllers/HostController.java b/racevisionGame/src/main/java/visualiser/Controllers/HostController.java index 1609e700..008276ef 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/HostController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/HostController.java @@ -1,21 +1,29 @@ package visualiser.Controllers; +import com.interactivemesh.jfx.importer.stl.StlMeshImporter; +import javafx.animation.AnimationTimer; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.fxml.FXML; -import javafx.scene.control.TextField; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; +import javafx.scene.control.SplitPane; +import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.GridPane; +import javafx.scene.shape.Box; +import javafx.scene.shape.Mesh; +import javafx.scene.shape.MeshView; +import javafx.scene.shape.Shape3D; +import javafx.scene.transform.Rotate; import mock.app.Event; -import org.xml.sax.SAXException; import mock.exceptions.EventConstructionException; -import shared.exceptions.InvalidBoatDataException; -import shared.exceptions.InvalidRaceDataException; -import shared.exceptions.InvalidRegattaDataException; -import shared.exceptions.XMLReaderException; +import visualiser.model.View3D; -import javax.xml.bind.JAXBException; -import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.net.Socket; import java.net.URL; +import java.util.Optional; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; @@ -26,27 +34,70 @@ import java.util.logging.Logger; public class HostController extends Controller { - @FXML - TextField gameNameField; +// @FXML +// TextField gameNameField; +// +// @FXML +// TextField hostNameField; @FXML - TextField hostNameField; + private ImageView imageView; @FXML AnchorPane hostWrapper; + @FXML + AnchorPane imagePane; + + @FXML + SplitPane splitPane; + + @FXML + AnchorPane specPane; + + @FXML + GridPane playerContainer; + private Event game; + private View3D view3D; @Override public void initialize(URL location, ResourceBundle resources) { + ObservableList shapes = FXCollections.observableArrayList(); + + view3D = new View3D(); + view3D.setItems(shapes); + playerContainer.add(view3D, 0,0); + + URL asset = HostController.class.getClassLoader().getResource("assets/V1.2 Complete Boat.stl"); + + StlMeshImporter importer = new StlMeshImporter(); + importer.read(asset); + MeshView mesh = new MeshView(importer.getImport()); + shapes.add(mesh); + + view3D.setPivot(mesh); + view3D.setDistance(50); + view3D.setYaw(45); + view3D.setPitch(20); + + Rotate rotation = new Rotate(0, Rotate.Y_AXIS); + mesh.getTransforms().addAll(rotation, new Rotate(-90, Rotate.X_AXIS)); + + AnimationTimer rotate = new AnimationTimer() { + @Override + public void handle(long now) { + rotation.setAngle(rotation.getAngle() + 0.1); + } + }; + rotate.start(); } /** * Hosts a game - * @throws IOException if socket cannot be connected to */ - public void hostGamePressed() throws IOException{ + public void hostGamePressed() { try { this.game = new Event(false); connectSocket("localhost", 4942); @@ -81,12 +132,34 @@ public class HostController extends Controller { * Hosts a game. */ public void hostGame(){ + splitPane.setResizableWithParent(specPane, false); + splitPane.lookupAll(".split-pane-divider").stream().forEach(div -> div.setMouseTransparent(true)); + imageView.fitWidthProperty().bind(imagePane.widthProperty()); + imageView.fitHeightProperty().bind(imagePane.heightProperty()); hostWrapper.setVisible(true); } + /** + * Menu button pressed. Prompt alert then return to menu + */ public void menuBtnPressed(){ - hostWrapper.setVisible(false); - parent.enterTitle(); + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setTitle("Quitting race"); + alert.setContentText("Do you wish to quit the race?"); + alert.setHeaderText("You are about to quit the race"); + Optional result = alert.showAndWait(); + if(result.get() == ButtonType.OK){ + hostWrapper.setVisible(false); + parent.enterTitle(); + } + } + + /** + * Start button pressed. Currently only prints out start + */ + public void startBtnPressed(){ + //System.out.println("Should start the race. This button is only visible for the host"); + hostGamePressed(); } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java index 07af2b49..d541c531 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/LobbyController.java @@ -21,7 +21,7 @@ import java.util.ResourceBundle; public class LobbyController extends Controller { @FXML - AnchorPane lobbyWrapper; + private AnchorPane lobbyWrapper; @FXML private TableView lobbyTable; @FXML diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java index 4fcda581..b6a53f0b 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java @@ -356,7 +356,7 @@ public class RaceController extends Controller { private void initialiseRaceCanvas(VisualiserRaceEvent race) { //Create canvas. - raceCanvas = new ResizableRaceCanvas(race); + raceCanvas = new ResizableRaceCanvas(race.getVisualiserRaceState()); //Set properties. raceCanvas.setMouseTransparent(true); diff --git a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java index 32e033c8..5617e3da 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java @@ -81,7 +81,6 @@ public class TitleController extends Controller { @Override public void initialize(URL location, ResourceBundle resources) { - } /** diff --git a/racevisionGame/src/main/java/visualiser/app/App.java b/racevisionGame/src/main/java/visualiser/app/App.java index eeae5a5d..31dcae24 100644 --- a/racevisionGame/src/main/java/visualiser/app/App.java +++ b/racevisionGame/src/main/java/visualiser/app/App.java @@ -96,15 +96,15 @@ public class App extends Application { ); updateMessage("Preparing ingredients . . ."); - Thread.sleep(1000); + Thread.sleep(200); for (int i = 0; i < burgerFilling.size(); i++) { - Thread.sleep(800); + Thread.sleep(100); updateProgress(i + 1, burgerFilling.size()); String nextFilling = burgerFilling.get(i); addedFilling.add(nextFilling); updateMessage("Adding the " + nextFilling + " . . ."); } - Thread.sleep(400); + Thread.sleep(100); updateMessage("Burger's done!"); return addedFilling; diff --git a/racevisionGame/src/main/java/visualiser/model/BoatDisplay3D.java b/racevisionGame/src/main/java/visualiser/model/BoatDisplay3D.java new file mode 100644 index 00000000..9314f5cd --- /dev/null +++ b/racevisionGame/src/main/java/visualiser/model/BoatDisplay3D.java @@ -0,0 +1,18 @@ +package visualiser.model; + +import com.interactivemesh.jfx.importer.Importer; +import javafx.scene.layout.Pane; + +/** + * Created by fwy13 on 29/08/17. + */ +public class BoatDisplay3D extends Pane { + + + public BoatDisplay3D(String filePath){ + super(); +// Shape3D +// this.getChildren().add(); + } + +} diff --git a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java index fc6a0858..03e86e27 100644 --- a/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java +++ b/racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java @@ -39,9 +39,9 @@ public class ResizableRaceCanvas extends ResizableCanvas { private Image sailsLuff = new Image("/images/sailsLuff.gif", 25, 10, false, false); /** - * The race we read data from and draw. + * The race state we read data from and draw. */ - private VisualiserRaceEvent visualiserRace; + private VisualiserRaceState raceState; private boolean annoName = true; @@ -56,14 +56,14 @@ public class ResizableRaceCanvas extends ResizableCanvas { /** * Constructs a {@link ResizableRaceCanvas} using a given {@link VisualiserRaceEvent}. - * @param visualiserRace The race that data is read from in order to be drawn. + * @param raceState The race state to be drawn. */ - public ResizableRaceCanvas(VisualiserRaceEvent visualiserRace) { + public ResizableRaceCanvas(VisualiserRaceState raceState) { super(); - this.visualiserRace = visualiserRace; + this.raceState = raceState; - RaceDataSource raceData = visualiserRace.getVisualiserRaceState().getRaceDataSource(); + RaceDataSource raceData = raceState.getRaceDataSource(); double lat1 = raceData.getMapTopLeft().getLatitude(); double long1 = raceData.getMapTopLeft().getLongitude(); @@ -276,8 +276,8 @@ public class ResizableRaceCanvas extends ResizableCanvas { boat.getCountry(), boat.getCurrentSpeed(), this.map.convertGPS(boat.getPosition()), - boat.getTimeToNextMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()), - boat.getTimeSinceLastMarkFormatted(this.visualiserRace.getVisualiserRaceState().getRaceClock().getCurrentTime()), + boat.getTimeToNextMarkFormatted(raceState.getRaceClock().getCurrentTime()), + boat.getTimeSinceLastMarkFormatted(raceState.getRaceClock().getCurrentTime()), Color.BLACK, 20 ); @@ -291,7 +291,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { */ private void drawBoats() { - List boats = new ArrayList<>(visualiserRace.getVisualiserRaceState().getBoats()); + List boats = new ArrayList<>(raceState.getBoats()); //Sort to ensure we draw boats in consistent order. boats.sort(Comparator.comparingInt(Boat::getSourceID)); @@ -510,7 +510,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { */ private void drawMarks() { - for (Mark mark : new ArrayList<>(visualiserRace.getVisualiserRaceState().getMarks())) { + for (Mark mark : new ArrayList<>(raceState.getMarks())) { drawMark(mark); } } @@ -574,7 +574,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { //Calculate the screen coordinates of the boundary. - List boundary = new ArrayList<>(visualiserRace.getVisualiserRaceState().getBoundary()); + List boundary = new ArrayList<>(raceState.getBoundary()); double[] xpoints = new double[boundary.size()]; double[] ypoints = new double[boundary.size()]; @@ -601,8 +601,8 @@ public class ResizableRaceCanvas extends ResizableCanvas { public void drawRace() { //Update RaceMap with new GPS values of race. - this.map.setGPSTopLeft(visualiserRace.getVisualiserRaceState().getRaceDataSource().getMapTopLeft()); - this.map.setGPSBotRight(visualiserRace.getVisualiserRaceState().getRaceDataSource().getMapBottomRight()); + this.map.setGPSTopLeft(raceState.getRaceDataSource().getMapTopLeft()); + this.map.setGPSBotRight(raceState.getRaceDataSource().getMapBottomRight()); clear(); @@ -627,7 +627,7 @@ public class ResizableRaceCanvas extends ResizableCanvas { * draws a transparent line around the course that shows the paths boats must travel */ public void drawRaceLine(){ - List legs = this.visualiserRace.getVisualiserRaceState().getLegs(); + List legs = raceState.getLegs(); GPSCoordinate legStartPoint = legs.get(0).getStartCompoundMark().getAverageGPSCoordinate(); GPSCoordinate nextStartPoint; for (int i = 0; i < legs.size() -1; i++) { diff --git a/racevisionGame/src/main/java/visualiser/model/View3D.java b/racevisionGame/src/main/java/visualiser/model/View3D.java new file mode 100644 index 00000000..6affb906 --- /dev/null +++ b/racevisionGame/src/main/java/visualiser/model/View3D.java @@ -0,0 +1,145 @@ +package visualiser.model; + +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.scene.Group; +import javafx.scene.PerspectiveCamera; +import javafx.scene.SubScene; +import javafx.scene.layout.Pane; +import javafx.scene.paint.Color; +import javafx.scene.shape.Shape3D; +import javafx.scene.transform.Rotate; +import javafx.scene.transform.Translate; + +/** + * Control for rendering 3D objects visible through a PerspectiveCamera. Implements Adapter Pattern to + * interface with camera, and allows clients to add shapes to the scene. All scenes contain sea plane and + * sky box, whose textures are set with special methods. + */ +public class View3D extends Pane { + /** + * Observable list of renderable items + */ + private ObservableList items; + /** + * Rendering container for shapes + */ + private Group world; + /** + * Near limit of view frustum + */ + private double nearClip; + /** + * Far limit of view frustum + */ + private double farClip; + /** + * Position camera pivots around + */ + private Translate pivot; + /** + * Distance of camera from pivot point + */ + private Translate distance; + /** + * Angle along ground between z-axis and camera + */ + private Rotate yaw; + /** + * Angle between ground plane and camera direction + */ + private Rotate pitch; + + /** + * Default constructor for View3D. Sets up Scene and PerspectiveCamera. + */ + public View3D() { + world = new Group(); + + SubScene scene = new SubScene(world, 300, 300); + scene.widthProperty().bind(this.widthProperty()); + scene.heightProperty().bind(this.heightProperty()); + scene.setFill(Color.BLACK); + + scene.setCamera(buildCamera()); + + this.getChildren().add(scene); + } + + /** + * Sets up camera view frustum and binds transformations + * @return perspective camera + */ + private PerspectiveCamera buildCamera() { + PerspectiveCamera camera = new PerspectiveCamera(true); + + // Set up view frustum + nearClip = 0.1; + farClip = 1000.0; + camera.setNearClip(nearClip); + camera.setFarClip(farClip); + + // Set up transformations + pivot = new Translate(); + distance = new Translate(); + yaw = new Rotate(0, Rotate.Y_AXIS); + pitch = new Rotate(0, Rotate.X_AXIS); + camera.getTransforms().addAll(pivot, yaw, pitch, distance); + + return camera; + } + + public void setItems(ObservableList items) { + this.items = items; + this.items.addListener((ListChangeListener) c -> { + while(c.next()) { + if (c.wasRemoved() || c.wasAdded()) { + for (Shape3D shape : c.getRemoved()) world.getChildren().remove(shape); + for (Shape3D shape : c.getAddedSubList()) world.getChildren().add(shape); + } + } + }); + } + + public void setNearClip(double nearClip) { + this.nearClip = nearClip; + } + + public void setFarClip(double farClip) { + this.farClip = farClip; + } + + /** + * Set object to centre on camera + * @param pivot centred object + */ + public void setPivot(Shape3D pivot) { + this.pivot.setX(pivot.getTranslateX()); + this.pivot.setY(pivot.getTranslateY()); + this.pivot.setZ(pivot.getTranslateZ()); + } + + /** + * Set distance of camera from pivot + * @param distance in units + */ + public void setDistance(double distance) { + this.distance.setZ(-distance); + } + + /** + * Set angle of camera from z-axis along ground + * @param yaw in degrees + */ + public void setYaw(double yaw) { + this.yaw.setAngle(yaw); + } + + /** + * Set elevation of camera + * @param pitch in degrees + */ + public void setPitch(double pitch) { + this.pitch.setAngle(-pitch); + } +} diff --git a/racevisionGame/src/main/resources/assets/V1.2 Complete Boat.stl b/racevisionGame/src/main/resources/assets/V1.2 Complete Boat.stl new file mode 100644 index 00000000..a952ca77 Binary files /dev/null and b/racevisionGame/src/main/resources/assets/V1.2 Complete Boat.stl differ diff --git a/racevisionGame/src/main/resources/visualiser/images/lobby.gif b/racevisionGame/src/main/resources/visualiser/images/lobby.gif new file mode 100644 index 00000000..c70d8df6 Binary files /dev/null and b/racevisionGame/src/main/resources/visualiser/images/lobby.gif differ diff --git a/racevisionGame/src/main/resources/visualiser/scenes/hostgame.fxml b/racevisionGame/src/main/resources/visualiser/scenes/hostgame.fxml index ced36627..ab14abaf 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/hostgame.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/hostgame.fxml @@ -1,40 +1,44 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/racevisionGame/src/main/resources/visualiser/scenes/main.fxml b/racevisionGame/src/main/resources/visualiser/scenes/main.fxml index 074a9b31..7aff44c0 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/main.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/main.fxml @@ -7,7 +7,7 @@ - + diff --git a/racevisionGame/src/main/resources/visualiser/scenes/title.fxml b/racevisionGame/src/main/resources/visualiser/scenes/title.fxml index f448a226..255381af 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/title.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/title.fxml @@ -1,61 +1,61 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +