/*
* ShootOFF - Software for Laser Dry Fire Training
* Copyright (C) 2016 phrack
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.shootoff.gui.pane;
import java.util.Optional;
import com.shootoff.camera.CameraManager;
import com.shootoff.camera.perspective.PerspectiveManager;
import com.shootoff.config.Configuration;
import com.shootoff.gui.CalibrationConfigurator;
import com.shootoff.gui.CalibrationListener;
import com.shootoff.gui.CalibrationManager;
import com.shootoff.gui.CalibrationOption;
import com.shootoff.gui.CanvasManager;
import com.shootoff.gui.MirroredCanvasManager;
import com.shootoff.gui.Resetter;
import com.shootoff.plugins.ProjectorTrainingExerciseBase;
import com.shootoff.targets.CameraViews;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class ProjectorSlide extends Slide implements CalibrationConfigurator {
private final Pane parentControls;
private final Pane parentBody;
private final Configuration config;
private final CameraViews cameraViews;
private final Stage shootOffStage;
private final Pane trainingExerciseContainer;
private final Resetter resetter;
private final ExerciseSlide exerciseSlide;
private final Button calibrateButton;
private ArenaBackgroundsSlide backgroundsSlide;
private ProjectorArenaPane arenaPane;
private Optional<CalibrationManager> calibrationManager = Optional.empty();
public ProjectorSlide(Pane parentControls, Pane parentBody, CameraViews cameraViews, Stage shootOffStage,
Pane trainingExerciseContainer, Resetter resetter, ExerciseSlide exerciseSlide) {
super(parentControls, parentBody);
this.parentControls = parentControls;
this.parentBody = parentBody;
config = Configuration.getConfig();
this.cameraViews = cameraViews;
this.shootOffStage = shootOffStage;
this.trainingExerciseContainer = trainingExerciseContainer;
this.resetter = resetter;
this.exerciseSlide = exerciseSlide;
calibrateButton = addSlideControlButton("Calibrate", (event) -> {
if (!calibrationManager.isPresent()) return;
final CalibrationManager calibrator = calibrationManager.get();
if (!calibrator.isCalibrating()) {
calibrator.enableCalibration();
} else {
calibrator.stopCalibration();
}
});
addSlideControlButton("Background", (event) -> {
backgroundsSlide.showControls();
backgroundsSlide.showBody();
});
addSlideControlButton("Courses", (event) -> {
final ArenaCoursesSlide coursesSlide = new ArenaCoursesSlide(parentControls, parentBody, arenaPane,
shootOffStage);
coursesSlide.setOnSlideHidden(() -> {
if (coursesSlide.choseCourse()) {
hide();
}
});
coursesSlide.showControls();
coursesSlide.showBody();
});
}
@Override
public CalibrationOption getCalibratedFeedBehavior() {
return config.getCalibratedFeedBehavior();
}
@Override
public void calibratedFeedBehaviorsChanged() {
if (calibrationManager.isPresent())
calibrationManager.get().configureArenaCamera(config.getCalibratedFeedBehavior());
if (arenaPane != null) arenaPane.getCanvasManager().setShowShots(config.showArenaShotMarkers());
}
@Override
public void toggleCalibrating(boolean isCalibrating) {
final Runnable toggleCalibrationAction = () -> {
if (isCalibrating)
calibrateButton.setText("Stop Calibrating");
else
calibrateButton.setText("Calibrate");
};
if (Platform.isFxApplicationThread()) {
toggleCalibrationAction.run();
} else {
Platform.runLater(toggleCalibrationAction);
}
}
public ProjectorArenaPane getArenaPane() {
return arenaPane;
}
public Optional<CalibrationManager> getCalibrationManager() {
return calibrationManager;
}
public void startArena() {
if (arenaPane != null) {
// Already started
return;
}
final Stage arenaStage = new Stage();
arenaPane = new ProjectorArenaPane(arenaStage, shootOffStage, trainingExerciseContainer, resetter, null);
// Prepare calibrating manager up front so that we can switch
// to the arena tab when it's ready (otherwise
// getSelectedCameraManager() will fail)
final CameraManager calibratingCameraManager = cameraViews.getSelectedCameraManager();
// Mirror panes so that anything that happens to one also
// happens to the other
final ProjectorArenaPane arenaTabPane = new ProjectorArenaPane(arenaStage, shootOffStage,
trainingExerciseContainer, resetter, cameraViews.getShotTimerModel());
arenaTabPane.prefWidthProperty().bind(arenaPane.prefWidthProperty());
arenaTabPane.prefHeightProperty().bind(arenaPane.prefHeightProperty());
cameraViews.addNonCameraView("Arena", arenaTabPane, arenaTabPane.getCanvasManager(), true, true);
arenaPane.setArenaPaneMirror(arenaTabPane);
final CanvasManager arenaCanvasManager = arenaPane.getCanvasManager();
arenaCanvasManager.setCameraManager(calibratingCameraManager);
if (!(arenaCanvasManager instanceof MirroredCanvasManager)) {
throw new AssertionError("Arena canvas manager is not of type MirroredCanvasManager");
}
final MirroredCanvasManager projectorCanvasManager = (MirroredCanvasManager) arenaCanvasManager;
final CanvasManager tabArenaCanvasManager = arenaTabPane.getCanvasManager();
if (!(tabArenaCanvasManager instanceof MirroredCanvasManager)) {
throw new AssertionError("Tab arena canvas manager is not of type MirroredCanvasManager");
}
final MirroredCanvasManager tabCanvasManager = (MirroredCanvasManager) tabArenaCanvasManager;
projectorCanvasManager.setMirroredManager(tabCanvasManager);
tabCanvasManager.setMirroredManager(projectorCanvasManager);
projectorCanvasManager.updateBackground(null, Optional.empty());
// This camera manager must be set to enable click-to-shoot for
// the arena tab
tabCanvasManager.setCameraManager(calibratingCameraManager);
// Final preparation to display
arenaStage.setTitle("Projector Arena");
arenaStage.setScene(new Scene(arenaPane));
arenaStage.setFullScreenExitHint("");
calibrationManager = Optional.of(new CalibrationManager(this, calibratingCameraManager, arenaPane, cameraViews,
null, exerciseSlide.getExerciseListener()));
calibrationManager.get().addCalibrationListener(new CalibrationListener() {
@Override
public void startCalibration() {}
@Override
public void calibrated(Optional<PerspectiveManager> perspectiveManager) {
if (Platform.isFxApplicationThread()) {
hide();
} else {
Platform.runLater(() -> hide());
}
}
});
arenaPane.setCalibrationManager(calibrationManager.get());
exerciseSlide.toggleProjectorExercises(false);
arenaPane.getCanvasManager().setShowShots(config.showArenaShotMarkers());
backgroundsSlide = new ArenaBackgroundsSlide(parentControls, parentBody, arenaPane, shootOffStage);
backgroundsSlide.setOnSlideHidden(() -> {
if (backgroundsSlide.choseBackground()) {
backgroundsSlide.setChoseBackground(false);
hide();
}
});
// Display the arena
calibrateButton.fire();
arenaPane.toggleArena();
arenaPane.autoPlaceArena();
arenaStage.setOnCloseRequest((e) -> {
arenaStage.setOnCloseRequest(null);
arenaPane.close();
arenaPane.setFeedCanvasManager(null);
arenaPane = null;
cameraViews.removeCameraView("Arena");
if (config.getExercise().isPresent()
&& config.getExercise().get() instanceof ProjectorTrainingExerciseBase) {
exerciseSlide.toggleProjectorExercises(true);
}
if (calibrationManager.isPresent()) {
if (calibrationManager.get().isCalibrating()) {
calibrationManager.get().stopCalibration();
} else {
calibrationManager.get().arenaClosing();
}
}
exerciseSlide.toggleProjectorExercises(true);
});
}
public void closeArena() {
if (arenaPane != null) {
arenaPane.getCanvasManager().close();
arenaPane.close();
}
}
}