Remove MovableRenderer and add support for renderer effects

pull/35/head
James Ball 2021-05-08 22:49:43 +01:00
rodzic 5179e711e7
commit f40ff434e3
19 zmienionych plików z 96 dodań i 57 usunięć

Wyświetl plik

@ -6,14 +6,14 @@
<groupId>sh.ball</groupId> <groupId>sh.ball</groupId>
<artifactId>osci-render</artifactId> <artifactId>osci-render</artifactId>
<version>1.0.3</version> <version>1.1.0</version>
<name>osci-render</name> <name>osci-render</name>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>15</maven.compiler.release> <maven.compiler.release>15</maven.compiler.release>
<javafx.version>15.0.1</javafx.version> <javafx.version>16</javafx.version>
<project.modulePath>${project.build.directory}\modules</project.modulePath> <project.modulePath>${project.build.directory}\modules</project.modulePath>
<appModule>oscirender</appModule> <appModule>oscirender</appModule>
<appMainClass>sh.ball.gui.Gui</appMainClass> <appMainClass>sh.ball.gui.Gui</appMainClass>

Wyświetl plik

@ -1,12 +0,0 @@
package sh.ball;
public interface MovableRenderer<S, T> extends Renderer<S> {
void setRotationSpeed(double speed);
void setTranslation(T translation);
void setTranslationSpeed(double speed);
void setScale(double scale);
}

Wyświetl plik

@ -1,10 +0,0 @@
package sh.ball;
public interface Renderer<T> extends Runnable {
void stop();
void setQuality(double quality);
void addFrame(T frame);
}

Wyświetl plik

@ -1,6 +1,5 @@
package sh.ball.audio; package sh.ball.audio;
import sh.ball.MovableRenderer;
import xt.audio.Enums.XtSample; import xt.audio.Enums.XtSample;
import xt.audio.Enums.XtSetup; import xt.audio.Enums.XtSetup;
import xt.audio.Enums.XtSystem; import xt.audio.Enums.XtSystem;
@ -18,6 +17,9 @@ import xt.audio.XtSafeBuffer;
import xt.audio.XtService; import xt.audio.XtService;
import xt.audio.XtStream; import xt.audio.XtStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
@ -26,7 +28,7 @@ import sh.ball.shapes.Vector2;
import java.util.List; import java.util.List;
public class AudioPlayer implements MovableRenderer<List<Shape>, Vector2> { public class AudioPlayer implements Renderer<List<Shape>> {
private static final int SAMPLE_RATE = 192000; private static final int SAMPLE_RATE = 192000;
private static final int BUFFER_SIZE = 20; private static final int BUFFER_SIZE = 20;
@ -36,6 +38,7 @@ public class AudioPlayer implements MovableRenderer<List<Shape>, Vector2> {
private final XtFormat FORMAT = new XtFormat(MIX, CHANNELS); private final XtFormat FORMAT = new XtFormat(MIX, CHANNELS);
private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE); private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
private Map<Object, Effect> effects = new HashMap<>();
private List<Shape> frame; private List<Shape> frame;
private int currentShape = 0; private int currentShape = 0;
private int audioFramesDrawn = 0; private int audioFramesDrawn = 0;
@ -76,7 +79,7 @@ public class AudioPlayer implements MovableRenderer<List<Shape>, Vector2> {
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 = shape.nextVector(drawingProgress); Vector2 nextVector = applyEffects(f, shape.nextVector(drawingProgress));
output[f * FORMAT.channels.outputs] = (float) nextVector.getX(); output[f * FORMAT.channels.outputs] = (float) nextVector.getX();
output[f * FORMAT.channels.outputs + 1] = (float) nextVector.getY(); output[f * FORMAT.channels.outputs + 1] = (float) nextVector.getY();
@ -97,6 +100,13 @@ public class AudioPlayer implements MovableRenderer<List<Shape>, Vector2> {
return 0; return 0;
} }
private Vector2 applyEffects(int frame, Vector2 vector) {
for (Effect effect : effects.values()) {
vector = effect.apply(frame, vector);
}
return vector;
}
private Shape rotate(Shape shape, double sampleRate) { private Shape rotate(Shape shape, double sampleRate) {
if (rotateSpeed != 0) { if (rotateSpeed != 0) {
shape = shape.rotate( shape = shape.rotate(
@ -135,22 +145,18 @@ public class AudioPlayer implements MovableRenderer<List<Shape>, Vector2> {
return shape; return shape;
} }
@Override
public void setRotationSpeed(double speed) { public void setRotationSpeed(double speed) {
this.rotateSpeed = speed; this.rotateSpeed = speed;
} }
@Override
public void setTranslation(Vector2 translation) { public void setTranslation(Vector2 translation) {
this.translateVector = translation; this.translateVector = translation;
} }
@Override
public void setTranslationSpeed(double speed) { public void setTranslationSpeed(double speed) {
translateSpeed = speed; translateSpeed = speed;
} }
@Override
public void setScale(double scale) { public void setScale(double scale) {
this.scale = scale; this.scale = scale;
} }
@ -218,6 +224,16 @@ public class AudioPlayer implements MovableRenderer<List<Shape>, Vector2> {
} }
} }
@Override
public void addEffect(Object identifier, Effect effect) {
effects.put(identifier, effect);
}
@Override
public void removeEffect(Object identifier) {
effects.remove(identifier);
}
private static final class Phase { private static final class Phase {
private double value = 0; private double value = 0;

Wyświetl plik

@ -0,0 +1,7 @@
package sh.ball.audio;
import sh.ball.shapes.Vector2;
public interface Effect {
Vector2 apply(int count, Vector2 vector);
}

Wyświetl plik

@ -1,8 +1,5 @@
package sh.ball.audio; package sh.ball.audio;
import sh.ball.FrameSet;
import sh.ball.Renderer;
public class FrameProducer<T> implements Runnable { public class FrameProducer<T> implements Runnable {
private final Renderer<T> renderer; private final Renderer<T> renderer;

Wyświetl plik

@ -1,4 +1,4 @@
package sh.ball; package sh.ball.audio;
public interface FrameSet<T> { public interface FrameSet<T> {

Wyświetl plik

@ -0,0 +1,14 @@
package sh.ball.audio;
public interface Renderer<T> extends Runnable {
void stop();
void setQuality(double quality);
void addFrame(T frame);
void addEffect(Object identifier, Effect effect);
void removeEffect(Object identifier);
}

Wyświetl plik

@ -1,7 +1,8 @@
package sh.ball.gui; package sh.ball.gui;
import sh.ball.MovableRenderer; import javafx.scene.control.*;
import sh.ball.audio.AudioPlayer; import sh.ball.audio.AudioPlayer;
import sh.ball.audio.Effect;
import sh.ball.audio.FrameProducer; import sh.ball.audio.FrameProducer;
import java.io.File; import java.io.File;
@ -17,11 +18,6 @@ import java.util.concurrent.Executors;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import javafx.stage.Stage; import javafx.stage.Stage;
@ -40,7 +36,8 @@ public class Controller implements Initializable {
private static final InputStream DEFAULT_OBJ = Controller.class.getResourceAsStream("/models/cube.obj"); private static final InputStream DEFAULT_OBJ = Controller.class.getResourceAsStream("/models/cube.obj");
private final FileChooser fileChooser = new FileChooser(); private final FileChooser fileChooser = new FileChooser();
private final MovableRenderer<List<Shape>, Vector2> renderer = new AudioPlayer(); // TODO: Reduce coupling on AudioPlayer
private final AudioPlayer renderer = new AudioPlayer();
private final ExecutorService executor = Executors.newSingleThreadExecutor(); private final ExecutorService executor = Executors.newSingleThreadExecutor();
private FrameProducer<List<Shape>> producer = new FrameProducer<>( private FrameProducer<List<Shape>> producer = new FrameProducer<>(
@ -86,6 +83,8 @@ public class Controller implements Initializable {
private TextField cameraYTextField; private TextField cameraYTextField;
@FXML @FXML
private TextField cameraZTextField; private TextField cameraZTextField;
@FXML
private CheckBox vectorCancellingCheckBox;
public Controller() throws IOException { public Controller() throws IOException {
} }
@ -135,6 +134,11 @@ public class Controller implements Initializable {
cameraYTextField.textProperty().addListener(cameraPosUpdate); cameraYTextField.textProperty().addListener(cameraPosUpdate);
cameraZTextField.textProperty().addListener(cameraPosUpdate); cameraZTextField.textProperty().addListener(cameraPosUpdate);
vectorCancellingCheckBox.selectedProperty().addListener((o, old, checked) ->
updateEffect(EffectType.VECTOR_CANCELLING, checked,
((count, v) -> count % 2 == 0 ? v.scale(-1) : v))
);
chooseFileButton.setOnAction(e -> { chooseFileButton.setOnAction(e -> {
File file = fileChooser.showOpenDialog(stage); File file = fileChooser.showOpenDialog(stage);
if (file != null) { if (file != null) {
@ -158,6 +162,14 @@ public class Controller implements Initializable {
} }
} }
private void updateEffect(EffectType type, boolean checked, Effect effect) {
if (checked) {
renderer.addEffect(type, effect);
} else {
renderer.removeEffect(type);
}
}
private void chooseFile(File file) { private void chooseFile(File file) {
try { try {
producer.stop(); producer.stop();

Wyświetl plik

@ -0,0 +1,5 @@
package sh.ball.gui;
enum EffectType {
VECTOR_CANCELLING
}

Wyświetl plik

@ -22,6 +22,7 @@ public class Gui extends Application {
stage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/icons/icon.png")))); stage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/icons/icon.png"))));
stage.setTitle("osci-render"); stage.setTitle("osci-render");
stage.setScene(new Scene(root)); stage.setScene(new Scene(root));
stage.setResizable(false);
controller.setStage(stage); controller.setStage(stage);

Wyświetl plik

@ -1,7 +1,7 @@
package sh.ball.parser; package sh.ball.parser;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import sh.ball.FrameSet; import sh.ball.audio.FrameSet;
import sh.ball.parser.obj.ObjParser; import sh.ball.parser.obj.ObjParser;
import sh.ball.parser.svg.SvgParser; import sh.ball.parser.svg.SvgParser;
import sh.ball.parser.txt.TextParser; import sh.ball.parser.txt.TextParser;

Wyświetl plik

@ -1,6 +1,6 @@
package sh.ball.parser.obj; package sh.ball.parser.obj;
import sh.ball.FrameSet; import sh.ball.audio.FrameSet;
import sh.ball.engine.Camera; import sh.ball.engine.Camera;
import sh.ball.engine.Vector3; import sh.ball.engine.Vector3;
import sh.ball.engine.WorldObject; import sh.ball.engine.WorldObject;

Wyświetl plik

@ -1,6 +1,6 @@
package sh.ball.parser.obj; package sh.ball.parser.obj;
import sh.ball.FrameSet; import sh.ball.audio.FrameSet;
import sh.ball.engine.Camera; import sh.ball.engine.Camera;
import sh.ball.engine.Vector3; import sh.ball.engine.Vector3;
import sh.ball.engine.WorldObject; import sh.ball.engine.WorldObject;

Wyświetl plik

@ -23,7 +23,7 @@ import org.unbescape.html.HtmlEscape;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import sh.ball.FrameSet; import sh.ball.audio.FrameSet;
import sh.ball.parser.FileParser; import sh.ball.parser.FileParser;
import sh.ball.shapes.ShapeFrameSet; import sh.ball.shapes.ShapeFrameSet;
import sh.ball.shapes.Shape; import sh.ball.shapes.Shape;

Wyświetl plik

@ -10,7 +10,7 @@ import java.util.stream.Collectors;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import sh.ball.FrameSet; import sh.ball.audio.FrameSet;
import sh.ball.parser.FileParser; import sh.ball.parser.FileParser;
import sh.ball.shapes.ShapeFrameSet; import sh.ball.shapes.ShapeFrameSet;
import sh.ball.parser.svg.SvgParser; import sh.ball.parser.svg.SvgParser;

Wyświetl plik

@ -1,6 +1,6 @@
package sh.ball.shapes; package sh.ball.shapes;
import sh.ball.FrameSet; import sh.ball.audio.FrameSet;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator; import java.awt.geom.PathIterator;

Wyświetl plik

@ -1,7 +1,6 @@
package sh.ball.shapes; package sh.ball.shapes;
import sh.ball.FrameSet; import sh.ball.audio.FrameSet;
import sh.ball.shapes.Shape;
import java.util.List; import java.util.List;

Wyświetl plik

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?> <?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?> <?import javafx.scene.control.Slider?>
<?import javafx.scene.control.SplitPane?> <?import javafx.scene.control.SplitPane?>
@ -11,17 +12,17 @@
<?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" vgap="10" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sh.ball.gui.Controller"> <GridPane alignment="center" hgap="10" prefWidth="400.0" vgap="10" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sh.ball.gui.Controller">
<columnConstraints> <columnConstraints>
<ColumnConstraints /> <ColumnConstraints />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints /> <RowConstraints />
</rowConstraints> </rowConstraints>
<AnchorPane prefHeight="279.0" prefWidth="400.0"> <AnchorPane prefHeight="602.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="15.0" mnemonicParsing="false" prefHeight="26.0" prefWidth="119.0" text="Choose File" />
<SplitPane dividerPositions="0.4723618090452261" layoutX="8.0" layoutY="56.0" orientation="VERTICAL" prefHeight="371.0" prefWidth="386.0"> <SplitPane dividerPositions="0.3406015037593984, 0.669548872180451" layoutX="8.0" layoutY="63.0" orientation="VERTICAL" prefHeight="533.0" prefWidth="386.0">
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="0.0" prefWidth="385.0"> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="271.0" prefWidth="385.0">
<Slider fx:id="rotateSpeedSlider" layoutX="116.0" layoutY="79.0" max="10.0" prefHeight="14.0" prefWidth="198.0" /> <Slider fx:id="rotateSpeedSlider" layoutX="116.0" layoutY="79.0" max="10.0" prefHeight="14.0" prefWidth="198.0" />
<Label layoutX="37.0" layoutY="77.0" text="Rotate speed" /> <Label layoutX="37.0" layoutY="77.0" text="Rotate speed" />
<Label fx:id="rotateSpeedLabel" layoutX="316.0" layoutY="77.0" text="0" /> <Label fx:id="rotateSpeedLabel" layoutX="316.0" layoutY="77.0" text="0" />
@ -40,8 +41,17 @@
<Slider fx:id="weightSlider" layoutX="116.0" layoutY="52.0" max="1000.0" prefHeight="14.0" prefWidth="198.0" value="100.0" /> <Slider fx:id="weightSlider" layoutX="116.0" layoutY="52.0" max="1000.0" prefHeight="14.0" prefWidth="198.0" value="100.0" />
<Label fx:id="weightLabel" layoutX="316.0" layoutY="51.0" text="100" /> <Label fx:id="weightLabel" layoutX="316.0" layoutY="51.0" text="100" />
</AnchorPane> </AnchorPane>
<TitledPane fx:id="objTitledPane" animated="false" collapsible="false" text="3D .obj file settings"> <TitledPane animated="false" collapsible="false" prefHeight="169.0" prefWidth="385.0" text="Effects" SplitPane.resizableWithParent="false">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0"> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<CheckBox fx:id="vectorCancellingCheckBox" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" text="Vector cancelling" />
</children>
</AnchorPane>
</content>
</TitledPane>
<TitledPane fx:id="objTitledPane" animated="false" collapsible="false" prefHeight="186.0" prefWidth="385.0" text="3D .obj file settings" SplitPane.resizableWithParent="false">
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="96.0" prefWidth="382.0">
<Slider fx:id="focalLengthSlider" blockIncrement="2.0" layoutX="116.0" layoutY="15.0" max="2.0" min="1.0E-5" prefHeight="14.0" prefWidth="198.0" value="1.0" /> <Slider fx:id="focalLengthSlider" blockIncrement="2.0" layoutX="116.0" layoutY="15.0" max="2.0" min="1.0E-5" prefHeight="14.0" prefWidth="198.0" value="1.0" />
<Label layoutX="43.0" layoutY="14.0" text="Focal length" /> <Label layoutX="43.0" layoutY="14.0" text="Focal length" />
<Label fx:id="focalLengthLabel" layoutX="316.0" layoutY="14.0" text="1" /> <Label fx:id="focalLengthLabel" layoutX="316.0" layoutY="14.0" text="1" />
@ -55,6 +65,6 @@
</AnchorPane> </AnchorPane>
</TitledPane> </TitledPane>
</SplitPane> </SplitPane>
<Label fx:id="fileLabel" layoutX="134.0" layoutY="20.0" /> <Label fx:id="fileLabel" layoutX="134.0" layoutY="20.0" maxWidth="250.0" />
</AnchorPane> </AnchorPane>
</GridPane> </GridPane>