kopia lustrzana https://github.com/jameshball/osci-render
commit
a1539eb6f8
|
@ -6,3 +6,6 @@
|
||||||
|
|
||||||
# Ignore local binaries for xt-audio
|
# Ignore local binaries for xt-audio
|
||||||
/win32-x64
|
/win32-x64
|
||||||
|
|
||||||
|
# Ignore any .wav file output
|
||||||
|
*.wav
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<groupId>sh.ball</groupId>
|
<groupId>sh.ball</groupId>
|
||||||
<artifactId>osci-render</artifactId>
|
<artifactId>osci-render</artifactId>
|
||||||
<version>1.2.1</version>
|
<version>1.3.0</version>
|
||||||
|
|
||||||
<name>osci-render</name>
|
<name>osci-render</name>
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import xt.audio.Structs.XtFormat;
|
||||||
import xt.audio.Structs.XtMix;
|
import xt.audio.Structs.XtMix;
|
||||||
import xt.audio.Structs.XtStreamParams;
|
import xt.audio.Structs.XtStreamParams;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
@ -21,16 +22,24 @@ import java.util.concurrent.BlockingQueue;
|
||||||
import sh.ball.shapes.Shape;
|
import sh.ball.shapes.Shape;
|
||||||
import sh.ball.shapes.Vector2;
|
import sh.ball.shapes.Vector2;
|
||||||
|
|
||||||
|
import javax.sound.sampled.AudioFormat;
|
||||||
|
import javax.sound.sampled.AudioInputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class AudioPlayer implements Renderer<List<Shape>> {
|
public class AudioPlayer implements Renderer<List<Shape>, AudioInputStream> {
|
||||||
|
|
||||||
private static final int BUFFER_SIZE = 20;
|
private static final int BUFFER_SIZE = 20;
|
||||||
|
private static final int BITS_PER_SAMPLE = 16;
|
||||||
|
private static final boolean SIGNED = true;
|
||||||
|
private static final boolean BIG_ENDIAN = false;
|
||||||
|
|
||||||
private final XtFormat format;
|
private final XtFormat format;
|
||||||
private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
|
private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
|
||||||
private final Map<Object, Effect> effects = new HashMap<>();
|
private final Map<Object, Effect> effects = new HashMap<>();
|
||||||
|
|
||||||
|
private ByteArrayOutputStream outputStream;
|
||||||
|
private boolean recording = false;
|
||||||
|
private int framesRecorded = 0;
|
||||||
private List<Shape> frame;
|
private List<Shape> frame;
|
||||||
private int currentShape = 0;
|
private int currentShape = 0;
|
||||||
private int audioFramesDrawn = 0;
|
private int audioFramesDrawn = 0;
|
||||||
|
@ -45,22 +54,35 @@ public class AudioPlayer implements Renderer<List<Shape>> {
|
||||||
this.format = new XtFormat(mix, channels);
|
this.format = new XtFormat(mix, channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int render(XtStream stream, XtBuffer buffer, Object user) throws InterruptedException {
|
private int render(XtStream stream, XtBuffer buffer, Object user) throws InterruptedException, IOException {
|
||||||
XtSafeBuffer safe = XtSafeBuffer.get(stream);
|
XtSafeBuffer safe = XtSafeBuffer.get(stream);
|
||||||
safe.lock(buffer);
|
safe.lock(buffer);
|
||||||
float[] output = (float[]) safe.getOutput();
|
float[] output = (float[]) safe.getOutput();
|
||||||
|
|
||||||
for (int f = 0; f < buffer.frames; f++) {
|
for (int f = 0; f < buffer.frames; f++) {
|
||||||
Shape shape = getCurrentShape();
|
Shape shape = getCurrentShape().setWeight(weight);
|
||||||
|
|
||||||
shape = shape.setWeight(weight);
|
|
||||||
|
|
||||||
double totalAudioFrames = shape.getWeight() * shape.getLength();
|
double totalAudioFrames = shape.getWeight() * shape.getLength();
|
||||||
double drawingProgress = totalAudioFrames == 0 ? 1 : audioFramesDrawn / totalAudioFrames;
|
double drawingProgress = totalAudioFrames == 0 ? 1 : audioFramesDrawn / totalAudioFrames;
|
||||||
Vector2 nextVector = applyEffects(f, shape.nextVector(drawingProgress));
|
Vector2 nextVector = applyEffects(f, shape.nextVector(drawingProgress));
|
||||||
|
|
||||||
output[f * format.channels.outputs] = (float) nextVector.getX();
|
float nextX = cutoff((float) nextVector.getX());
|
||||||
output[f * format.channels.outputs + 1] = (float) nextVector.getY();
|
float nextY = cutoff((float) nextVector.getY());
|
||||||
|
|
||||||
|
output[f * format.channels.outputs] = nextX;
|
||||||
|
output[f * format.channels.outputs + 1] = nextY;
|
||||||
|
|
||||||
|
if (recording) {
|
||||||
|
int left = (int)(nextX * Short.MAX_VALUE);
|
||||||
|
int right = (int)(nextY * Short.MAX_VALUE);
|
||||||
|
|
||||||
|
outputStream.write((byte) left);
|
||||||
|
outputStream.write((byte)(left >> 8));
|
||||||
|
outputStream.write((byte) right);
|
||||||
|
outputStream.write((byte)(right >> 8));
|
||||||
|
|
||||||
|
framesRecorded++;
|
||||||
|
}
|
||||||
|
|
||||||
audioFramesDrawn++;
|
audioFramesDrawn++;
|
||||||
|
|
||||||
|
@ -78,6 +100,15 @@ public class AudioPlayer implements Renderer<List<Shape>> {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float cutoff(float value) {
|
||||||
|
if (value < -1) {
|
||||||
|
return -1;
|
||||||
|
} else if (value > 1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
private Vector2 applyEffects(int frame, Vector2 vector) {
|
private Vector2 applyEffects(int frame, Vector2 vector) {
|
||||||
for (Effect effect : effects.values()) {
|
for (Effect effect : effects.values()) {
|
||||||
vector = effect.apply(frame, vector);
|
vector = effect.apply(frame, vector);
|
||||||
|
@ -163,4 +194,21 @@ public class AudioPlayer implements Renderer<List<Shape>> {
|
||||||
effects.remove(identifier);
|
effects.remove(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startRecord() {
|
||||||
|
outputStream = new ByteArrayOutputStream();
|
||||||
|
framesRecorded = 0;
|
||||||
|
recording = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AudioInputStream stopRecord() {
|
||||||
|
recording = false;
|
||||||
|
byte[] input = outputStream.toByteArray();
|
||||||
|
outputStream = null;
|
||||||
|
|
||||||
|
AudioFormat audioFormat = new AudioFormat(format.mix.rate, BITS_PER_SAMPLE, format.channels.outputs, SIGNED, BIG_ENDIAN);
|
||||||
|
|
||||||
|
return new AudioInputStream(new ByteArrayInputStream(input), audioFormat, framesRecorded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package sh.ball.audio;
|
package sh.ball.audio;
|
||||||
|
|
||||||
public class FrameProducer<T> implements Runnable {
|
public class FrameProducer<S, T> implements Runnable {
|
||||||
|
|
||||||
private final Renderer<T> renderer;
|
private final Renderer<S, T> renderer;
|
||||||
private final FrameSet<T> frames;
|
private final FrameSet<S> frames;
|
||||||
|
|
||||||
private boolean running;
|
private boolean running;
|
||||||
|
|
||||||
public FrameProducer(Renderer<T> renderer, FrameSet<T> frames) {
|
public FrameProducer(Renderer<S, T> renderer, FrameSet<S> frames) {
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.frames = frames;
|
this.frames = frames;
|
||||||
}
|
}
|
||||||
|
@ -24,14 +24,7 @@ public class FrameProducer<T> implements Runnable {
|
||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object setFrameSettings(Object settings) {
|
public void setFrameSettings(Object settings) {
|
||||||
return setFrameSettings(settings, false);
|
frames.setFrameSettings(settings);
|
||||||
}
|
|
||||||
|
|
||||||
public Object setFrameSettings(Object settings, boolean flushFrames) {
|
|
||||||
if (flushFrames) {
|
|
||||||
renderer.flushFrames();
|
|
||||||
}
|
|
||||||
return frames.setFrameSettings(settings);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ public interface FrameSet<T> {
|
||||||
|
|
||||||
T next();
|
T next();
|
||||||
|
|
||||||
Object setFrameSettings(Object settings);
|
void setFrameSettings(Object settings);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,21 @@ package sh.ball.audio;
|
||||||
|
|
||||||
import sh.ball.audio.effect.Effect;
|
import sh.ball.audio.effect.Effect;
|
||||||
|
|
||||||
public interface Renderer<T> extends Runnable {
|
public interface Renderer<S, T> extends Runnable {
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void setQuality(double quality);
|
void setQuality(double quality);
|
||||||
|
|
||||||
void addFrame(T frame);
|
void addFrame(S frame);
|
||||||
|
|
||||||
void flushFrames();
|
void flushFrames();
|
||||||
|
|
||||||
void addEffect(Object identifier, Effect effect);
|
void addEffect(Object identifier, Effect effect);
|
||||||
|
|
||||||
void removeEffect(Object identifier);
|
void removeEffect(Object identifier);
|
||||||
|
|
||||||
|
void startRecord();
|
||||||
|
|
||||||
|
T stopRecord();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
@ -26,12 +28,14 @@ import javafx.fxml.Initializable;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
import javax.sound.sampled.AudioFileFormat;
|
||||||
|
import javax.sound.sampled.AudioInputStream;
|
||||||
|
import javax.sound.sampled.AudioSystem;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import sh.ball.audio.effect.TranslateEffect;
|
import sh.ball.audio.effect.TranslateEffect;
|
||||||
import sh.ball.engine.Vector3;
|
import sh.ball.engine.Vector3;
|
||||||
import sh.ball.parser.obj.ObjFrameSettings;
|
|
||||||
import sh.ball.parser.obj.ObjSettingsFactory;
|
import sh.ball.parser.obj.ObjSettingsFactory;
|
||||||
import sh.ball.parser.obj.ObjParser;
|
import sh.ball.parser.obj.ObjParser;
|
||||||
import sh.ball.parser.ParserFactory;
|
import sh.ball.parser.ParserFactory;
|
||||||
|
@ -45,14 +49,15 @@ public class Controller implements Initializable {
|
||||||
private static final double DEFAULT_ROTATE_SPEED = 0.1;
|
private static final double DEFAULT_ROTATE_SPEED = 0.1;
|
||||||
|
|
||||||
private final FileChooser fileChooser = new FileChooser();
|
private final FileChooser fileChooser = new FileChooser();
|
||||||
private final Renderer<List<Shape>> renderer;
|
private final Renderer<List<Shape>, AudioInputStream> renderer;
|
||||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
private final RotateEffect rotateEffect = new RotateEffect(SAMPLE_RATE);
|
private final RotateEffect rotateEffect = new RotateEffect(SAMPLE_RATE);
|
||||||
private final TranslateEffect translateEffect = new TranslateEffect(SAMPLE_RATE);
|
private final TranslateEffect translateEffect = new TranslateEffect(SAMPLE_RATE);
|
||||||
private final ScaleEffect scaleEffect = new ScaleEffect();
|
private final ScaleEffect scaleEffect = new ScaleEffect();
|
||||||
|
|
||||||
private FrameProducer<List<Shape>> producer;
|
private FrameProducer<List<Shape>, AudioInputStream> producer;
|
||||||
|
private boolean recording = false;
|
||||||
|
|
||||||
private Stage stage;
|
private Stage stage;
|
||||||
|
|
||||||
|
@ -61,6 +66,10 @@ public class Controller implements Initializable {
|
||||||
@FXML
|
@FXML
|
||||||
private Label fileLabel;
|
private Label fileLabel;
|
||||||
@FXML
|
@FXML
|
||||||
|
private Button recordButton;
|
||||||
|
@FXML
|
||||||
|
private Label recordLabel;
|
||||||
|
@FXML
|
||||||
private TextField translationXTextField;
|
private TextField translationXTextField;
|
||||||
@FXML
|
@FXML
|
||||||
private TextField translationYTextField;
|
private TextField translationYTextField;
|
||||||
|
@ -101,7 +110,7 @@ public class Controller implements Initializable {
|
||||||
@FXML
|
@FXML
|
||||||
private Slider bitCrushSlider;
|
private Slider bitCrushSlider;
|
||||||
|
|
||||||
public Controller(Renderer<List<Shape>> renderer) throws IOException {
|
public Controller(Renderer<List<Shape>, AudioInputStream> renderer) throws IOException {
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.producer = new FrameProducer<>(
|
this.producer = new FrameProducer<>(
|
||||||
renderer,
|
renderer,
|
||||||
|
@ -163,7 +172,7 @@ public class Controller implements Initializable {
|
||||||
tryParse(cameraXTextField.getText()),
|
tryParse(cameraXTextField.getText()),
|
||||||
tryParse(cameraYTextField.getText()),
|
tryParse(cameraYTextField.getText()),
|
||||||
tryParse(cameraZTextField.getText())
|
tryParse(cameraZTextField.getText())
|
||||||
)), true);
|
)));
|
||||||
|
|
||||||
cameraXTextField.textProperty().addListener(cameraPosUpdate);
|
cameraXTextField.textProperty().addListener(cameraPosUpdate);
|
||||||
cameraYTextField.textProperty().addListener(cameraPosUpdate);
|
cameraYTextField.textProperty().addListener(cameraPosUpdate);
|
||||||
|
@ -195,6 +204,15 @@ public class Controller implements Initializable {
|
||||||
bitCrushSlider.valueProperty().addListener(bitCrushListener);
|
bitCrushSlider.valueProperty().addListener(bitCrushListener);
|
||||||
bitCrushCheckBox.selectedProperty().addListener(bitCrushListener);
|
bitCrushCheckBox.selectedProperty().addListener(bitCrushListener);
|
||||||
|
|
||||||
|
fileChooser.setInitialFileName("out.wav");
|
||||||
|
fileChooser.getExtensionFilters().addAll(
|
||||||
|
new FileChooser.ExtensionFilter("All Files", "*.*"),
|
||||||
|
new FileChooser.ExtensionFilter("WAV Files", "*.wav"),
|
||||||
|
new FileChooser.ExtensionFilter("Wavefront OBJ Files", "*.obj"),
|
||||||
|
new FileChooser.ExtensionFilter("SVG Files", "*.svg"),
|
||||||
|
new FileChooser.ExtensionFilter("Text Files", "*.txt")
|
||||||
|
);
|
||||||
|
|
||||||
chooseFileButton.setOnAction(e -> {
|
chooseFileButton.setOnAction(e -> {
|
||||||
File file = fileChooser.showOpenDialog(stage);
|
File file = fileChooser.showOpenDialog(stage);
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
|
@ -202,6 +220,8 @@ public class Controller implements Initializable {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
recordButton.setOnAction(event -> toggleRecord());
|
||||||
|
|
||||||
setObjectRotateSpeed(DEFAULT_ROTATE_SPEED);
|
setObjectRotateSpeed(DEFAULT_ROTATE_SPEED);
|
||||||
|
|
||||||
renderer.addEffect(EffectType.SCALE, scaleEffect);
|
renderer.addEffect(EffectType.SCALE, scaleEffect);
|
||||||
|
@ -212,14 +232,34 @@ public class Controller implements Initializable {
|
||||||
new Thread(renderer).start();
|
new Thread(renderer).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void toggleRecord() {
|
||||||
|
recording = !recording;
|
||||||
|
if (recording) {
|
||||||
|
recordLabel.setText("Recording...");
|
||||||
|
recordButton.setText("Stop Recording");
|
||||||
|
renderer.startRecord();
|
||||||
|
} else {
|
||||||
|
recordButton.setText("Record");
|
||||||
|
AudioInputStream input = renderer.stopRecord();
|
||||||
|
try {
|
||||||
|
File file = fileChooser.showSaveDialog(stage);
|
||||||
|
SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
|
||||||
|
Date date = new Date(System.currentTimeMillis());
|
||||||
|
if (file == null) {
|
||||||
|
file = new File("out-" + formatter.format(date) + ".wav");
|
||||||
|
}
|
||||||
|
AudioSystem.write(input, AudioFileFormat.Type.WAVE, file);
|
||||||
|
input.close();
|
||||||
|
recordLabel.setText("Saved to " + file.getAbsolutePath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
recordLabel.setText("Error saving file");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setFocalLength(double focalLength) {
|
private void setFocalLength(double focalLength) {
|
||||||
Vector3 pos = (Vector3) producer.setFrameSettings(
|
producer.setFrameSettings(ObjSettingsFactory.focalLength(focalLength));
|
||||||
ObjSettingsFactory.focalLength(focalLength),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
cameraXTextField.setText(String.valueOf(pos.getX()));
|
|
||||||
cameraYTextField.setText(String.valueOf(pos.getY()));
|
|
||||||
cameraZTextField.setText(String.valueOf(pos.getZ()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setObjectRotateSpeed(double rotateSpeed) {
|
private void setObjectRotateSpeed(double rotateSpeed) {
|
||||||
|
|
|
@ -12,15 +12,13 @@ public class ObjFrameSet implements FrameSet<List<Shape>> {
|
||||||
|
|
||||||
private final WorldObject object;
|
private final WorldObject object;
|
||||||
private final Camera camera;
|
private final Camera camera;
|
||||||
private final boolean isDefaultPosition;
|
|
||||||
|
|
||||||
private Vector3 rotation = new Vector3();
|
private Vector3 rotation = new Vector3();
|
||||||
private Double rotateSpeed = 0.0;
|
private Double rotateSpeed = 0.0;
|
||||||
|
|
||||||
public ObjFrameSet(WorldObject object, Camera camera, boolean isDefaultPosition) {
|
public ObjFrameSet(WorldObject object, Camera camera) {
|
||||||
this.object = object;
|
this.object = object;
|
||||||
this.camera = camera;
|
this.camera = camera;
|
||||||
this.isDefaultPosition = isDefaultPosition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,13 +29,10 @@ public class ObjFrameSet implements FrameSet<List<Shape>> {
|
||||||
|
|
||||||
// TODO: Refactor!
|
// TODO: Refactor!
|
||||||
@Override
|
@Override
|
||||||
public Object setFrameSettings(Object settings) {
|
public void setFrameSettings(Object settings) {
|
||||||
if (settings instanceof ObjFrameSettings obj) {
|
if (settings instanceof ObjFrameSettings obj) {
|
||||||
if (obj.focalLength != null && camera.getFocalLength() != obj.focalLength) {
|
if (obj.focalLength != null && camera.getFocalLength() != obj.focalLength) {
|
||||||
camera.setFocalLength(obj.focalLength);
|
camera.setFocalLength(obj.focalLength);
|
||||||
if (isDefaultPosition) {
|
|
||||||
camera.findZPos(object);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (obj.cameraPos != null && camera.getPos() != obj.cameraPos) {
|
if (obj.cameraPos != null && camera.getPos() != obj.cameraPos) {
|
||||||
camera.setPos(obj.cameraPos);
|
camera.setPos(obj.cameraPos);
|
||||||
|
@ -52,7 +47,5 @@ public class ObjFrameSet implements FrameSet<List<Shape>> {
|
||||||
object.resetRotation();
|
object.resetRotation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return camera.getPos();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,12 +50,9 @@ public class ObjParser extends FileParser<FrameSet<List<Shape>>> {
|
||||||
@Override
|
@Override
|
||||||
public FrameSet<List<Shape>> parse() throws IllegalArgumentException, IOException {
|
public FrameSet<List<Shape>> parse() throws IllegalArgumentException, IOException {
|
||||||
object = new WorldObject(input);
|
object = new WorldObject(input);
|
||||||
|
|
||||||
if (isDefaultPosition) {
|
|
||||||
camera.findZPos(object);
|
camera.findZPos(object);
|
||||||
}
|
|
||||||
|
|
||||||
return new ObjFrameSet(object, camera, isDefaultPosition);
|
return new ObjFrameSet(object, camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If camera position arguments haven't been specified, automatically work out the position of
|
// If camera position arguments haven't been specified, automatically work out the position of
|
||||||
|
|
|
@ -40,9 +40,7 @@ public abstract class Shape implements FrameSet<List<Shape>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object setFrameSettings(Object settings) {
|
public void setFrameSettings(Object settings) {}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SHAPE HELPER FUNCTIONS */
|
/* SHAPE HELPER FUNCTIONS */
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,5 @@ public class ShapeFrameSet implements FrameSet<List<Shape>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object setFrameSettings(Object settings) {
|
public void setFrameSettings(Object settings) {}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,16 +12,16 @@
|
||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<?import javafx.scene.layout.RowConstraints?>
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
|
|
||||||
<GridPane alignment="center" hgap="10" prefHeight="719.0" prefWidth="400.0" vgap="10" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1">
|
<GridPane alignment="center" hgap="10" prefHeight="790.0" prefWidth="400.0" vgap="10" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints />
|
<ColumnConstraints />
|
||||||
</columnConstraints>
|
</columnConstraints>
|
||||||
<rowConstraints>
|
<rowConstraints>
|
||||||
<RowConstraints />
|
<RowConstraints />
|
||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<AnchorPane prefHeight="737.0" prefWidth="400.0">
|
<AnchorPane prefHeight="810.0" prefWidth="400.0">
|
||||||
<Button fx:id="chooseFileButton" layoutX="8.0" layoutY="15.0" mnemonicParsing="false" prefHeight="26.0" prefWidth="119.0" text="Choose File" />
|
<Button fx:id="chooseFileButton" layoutX="8.0" layoutY="24.0" mnemonicParsing="false" prefHeight="26.0" prefWidth="114.0" text="Choose File" />
|
||||||
<SplitPane dividerPositions="0.31499312242090777, 0.6158872077028884" layoutX="6.0" layoutY="63.0" orientation="VERTICAL" prefHeight="649.0" prefWidth="388.0">
|
<SplitPane dividerPositions="0.31499312242090777, 0.6158872077028884" layoutX="6.0" layoutY="118.0" orientation="VERTICAL" prefHeight="666.0" prefWidth="388.0">
|
||||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="178.0" prefWidth="396.0">
|
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="178.0" prefWidth="396.0">
|
||||||
<Slider fx:id="rotateSpeedSlider" blockIncrement="0.05" layoutX="116.0" layoutY="90.0" majorTickUnit="1.0" max="10.0" prefHeight="38.0" prefWidth="247.0" showTickLabels="true" showTickMarks="true" />
|
<Slider fx:id="rotateSpeedSlider" blockIncrement="0.05" layoutX="116.0" layoutY="90.0" majorTickUnit="1.0" max="10.0" prefHeight="38.0" prefWidth="247.0" showTickLabels="true" showTickMarks="true" />
|
||||||
<Label layoutX="37.0" layoutY="88.0" text="Rotate speed" />
|
<Label layoutX="37.0" layoutY="88.0" text="Rotate speed" />
|
||||||
|
@ -69,10 +69,12 @@
|
||||||
<TextField fx:id="rotateYTextField" layoutX="218.0" layoutY="139.0" prefHeight="26.0" prefWidth="58.0" text="0" />
|
<TextField fx:id="rotateYTextField" layoutX="218.0" layoutY="139.0" prefHeight="26.0" prefWidth="58.0" text="0" />
|
||||||
<Label layoutX="283.0" layoutY="143.0" text="z :" />
|
<Label layoutX="283.0" layoutY="143.0" text="z :" />
|
||||||
<TextField fx:id="rotateZTextField" layoutX="302.0" layoutY="139.0" prefHeight="26.0" prefWidth="58.0" text="0" />
|
<TextField fx:id="rotateZTextField" layoutX="302.0" layoutY="139.0" prefHeight="26.0" prefWidth="58.0" text="0" />
|
||||||
<Button fx:id="resetRotationButton" layoutX="145.0" layoutY="183.0" mnemonicParsing="false" text="Reset Rotation" />
|
<Button fx:id="resetRotationButton" layoutX="145.0" layoutY="189.0" mnemonicParsing="false" text="Reset Rotation" />
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
</TitledPane>
|
</TitledPane>
|
||||||
</SplitPane>
|
</SplitPane>
|
||||||
<Label fx:id="fileLabel" layoutX="134.0" layoutY="20.0" maxWidth="250.0" />
|
<Label fx:id="fileLabel" layoutX="140.0" layoutY="29.0" maxWidth="250.0" />
|
||||||
|
<Button fx:id="recordButton" layoutX="8.0" layoutY="68.0" mnemonicParsing="false" prefHeight="26.0" prefWidth="114.0" text="Record" />
|
||||||
|
<Label fx:id="recordLabel" layoutX="140.0" layoutY="73.0" maxWidth="250.0" />
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
|
|
Ładowanie…
Reference in New Issue