Remove MovableRenderer and add support for renderer effects

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

Wyświetl plik

@ -6,14 +6,14 @@
<groupId>sh.ball</groupId>
<artifactId>osci-render</artifactId>
<version>1.0.3</version>
<version>1.1.0</version>
<name>osci-render</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<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>
<appModule>oscirender</appModule>
<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;
import sh.ball.MovableRenderer;
import xt.audio.Enums.XtSample;
import xt.audio.Enums.XtSetup;
import xt.audio.Enums.XtSystem;
@ -18,6 +17,9 @@ import xt.audio.XtSafeBuffer;
import xt.audio.XtService;
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.BlockingQueue;
@ -26,7 +28,7 @@ import sh.ball.shapes.Vector2;
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 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 BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
private Map<Object, Effect> effects = new HashMap<>();
private List<Shape> frame;
private int currentShape = 0;
private int audioFramesDrawn = 0;
@ -76,7 +79,7 @@ public class AudioPlayer implements MovableRenderer<List<Shape>, Vector2> {
double totalAudioFrames = shape.getWeight() * shape.getLength();
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 + 1] = (float) nextVector.getY();
@ -97,6 +100,13 @@ public class AudioPlayer implements MovableRenderer<List<Shape>, Vector2> {
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) {
if (rotateSpeed != 0) {
shape = shape.rotate(
@ -135,22 +145,18 @@ public class AudioPlayer implements MovableRenderer<List<Shape>, Vector2> {
return shape;
}
@Override
public void setRotationSpeed(double speed) {
this.rotateSpeed = speed;
}
@Override
public void setTranslation(Vector2 translation) {
this.translateVector = translation;
}
@Override
public void setTranslationSpeed(double speed) {
translateSpeed = speed;
}
@Override
public void setScale(double 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 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;
import sh.ball.FrameSet;
import sh.ball.Renderer;
public class FrameProducer<T> implements Runnable {
private final Renderer<T> renderer;

Wyświetl plik

@ -1,4 +1,4 @@
package sh.ball;
package sh.ball.audio;
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;
import sh.ball.MovableRenderer;
import javafx.scene.control.*;
import sh.ball.audio.AudioPlayer;
import sh.ball.audio.Effect;
import sh.ball.audio.FrameProducer;
import java.io.File;
@ -17,11 +18,6 @@ import java.util.concurrent.Executors;
import javafx.beans.InvalidationListener;
import javafx.fxml.FXML;
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.Stage;
@ -40,7 +36,8 @@ public class Controller implements Initializable {
private static final InputStream DEFAULT_OBJ = Controller.class.getResourceAsStream("/models/cube.obj");
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 FrameProducer<List<Shape>> producer = new FrameProducer<>(
@ -86,6 +83,8 @@ public class Controller implements Initializable {
private TextField cameraYTextField;
@FXML
private TextField cameraZTextField;
@FXML
private CheckBox vectorCancellingCheckBox;
public Controller() throws IOException {
}
@ -135,6 +134,11 @@ public class Controller implements Initializable {
cameraYTextField.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 -> {
File file = fileChooser.showOpenDialog(stage);
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) {
try {
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.setTitle("osci-render");
stage.setScene(new Scene(root));
stage.setResizable(false);
controller.setStage(stage);

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -1,6 +1,6 @@
package sh.ball.parser.obj;
import sh.ball.FrameSet;
import sh.ball.audio.FrameSet;
import sh.ball.engine.Camera;
import sh.ball.engine.Vector3;
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.Node;
import org.xml.sax.SAXException;
import sh.ball.FrameSet;
import sh.ball.audio.FrameSet;
import sh.ball.parser.FileParser;
import sh.ball.shapes.ShapeFrameSet;
import sh.ball.shapes.Shape;

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.control.SplitPane?>
@ -11,17 +12,17 @@
<?import javafx.scene.layout.GridPane?>
<?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>
<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" />
<SplitPane dividerPositions="0.4723618090452261" layoutX="8.0" layoutY="56.0" orientation="VERTICAL" prefHeight="371.0" prefWidth="386.0">
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="0.0" prefWidth="385.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="271.0" prefWidth="385.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 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" />
<Label fx:id="weightLabel" layoutX="316.0" layoutY="51.0" text="100" />
</AnchorPane>
<TitledPane fx:id="objTitledPane" animated="false" collapsible="false" text="3D .obj file settings">
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<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">
<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" />
<Label layoutX="43.0" layoutY="14.0" text="Focal length" />
<Label fx:id="focalLengthLabel" layoutX="316.0" layoutY="14.0" text="1" />
@ -55,6 +65,6 @@
</AnchorPane>
</TitledPane>
</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>
</GridPane>