Add bit crush effect and decrease latency of render update

pull/35/head
James Ball 2021-05-09 20:58:40 +01:00
rodzic 2172478acf
commit dbd55e96ea
14 zmienionych plików z 99 dodań i 31 usunięć

Wyświetl plik

@ -6,7 +6,7 @@
<groupId>sh.ball</groupId>
<artifactId>osci-render</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
<name>osci-render</name>

Wyświetl plik

@ -1,5 +1,6 @@
package sh.ball.audio;
import sh.ball.audio.effect.Effect;
import xt.audio.Enums.XtSample;
import xt.audio.Enums.XtSetup;
import xt.audio.Enums.XtSystem;
@ -17,7 +18,6 @@ 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;
@ -224,6 +224,11 @@ public class AudioPlayer implements Renderer<List<Shape>> {
}
}
@Override
public void flushFrames() {
frameQueue.clear();
}
@Override
public void addEffect(Object identifier, Effect effect) {
effects.put(identifier, effect);

Wyświetl plik

@ -24,7 +24,8 @@ public class FrameProducer<T> implements Runnable {
running = false;
}
public void setFrameSettings(Object settings) {
frames.setFrameSettings(settings);
public Object setFrameSettings(Object settings) {
renderer.flushFrames();
return frames.setFrameSettings(settings);
}
}

Wyświetl plik

@ -4,5 +4,5 @@ public interface FrameSet<T> {
T next();
void setFrameSettings(Object settings);
Object setFrameSettings(Object settings);
}

Wyświetl plik

@ -1,5 +1,7 @@
package sh.ball.audio;
import sh.ball.audio.effect.Effect;
public interface Renderer<T> extends Runnable {
void stop();
@ -8,6 +10,8 @@ public interface Renderer<T> extends Runnable {
void addFrame(T frame);
void flushFrames();
void addEffect(Object identifier, Effect effect);
void removeEffect(Object identifier);

Wyświetl plik

@ -1,4 +1,4 @@
package sh.ball.audio;
package sh.ball.audio.effect;
import sh.ball.shapes.Vector2;

Wyświetl plik

@ -0,0 +1,6 @@
package sh.ball.audio.effect;
public enum EffectType {
VECTOR_CANCELLING,
BIT_CRUSH
}

Wyświetl plik

@ -0,0 +1,26 @@
package sh.ball.audio.effect;
import sh.ball.shapes.Vector2;
public class EventFactory {
public static Effect vectorCancelling(int frequency) {
return (count, v) -> count % frequency == 0 ? v.scale(-1) : v;
}
public static Effect bitCrush(double value) {
return (count, v) -> {
double x = v.getX();
double y = v.getY();
return new Vector2(round(x, value), round(y, value));
};
}
private static double round(double value, double places) {
if (places < 0) throw new IllegalArgumentException();
long factor = (long) Math.pow(10, places);
value = value * factor;
long tmp = Math.round(value);
return (double) tmp / factor;
}
}

Wyświetl plik

@ -2,13 +2,15 @@ package sh.ball.gui;
import javafx.scene.control.*;
import sh.ball.audio.AudioPlayer;
import sh.ball.audio.Effect;
import sh.ball.audio.effect.Effect;
import sh.ball.audio.FrameProducer;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.EventListener;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
@ -21,9 +23,13 @@ import javafx.fxml.Initializable;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import sh.ball.audio.effect.EffectType;
import sh.ball.audio.effect.EventFactory;
import sh.ball.engine.Vector3;
import sh.ball.parser.obj.ObjFrameSettings;
import sh.ball.parser.obj.ObjParser;
@ -87,6 +93,10 @@ public class Controller implements Initializable {
private CheckBox vectorCancellingCheckBox;
@FXML
private Slider vectorCancellingSlider;
@FXML
private CheckBox bitCrushCheckBox;
@FXML
private Slider bitCrushSlider;
public Controller() throws IOException {
}
@ -111,7 +121,9 @@ public class Controller implements Initializable {
private void initializeEffectTypes() {
effectTypes = Map.of(
EffectType.VECTOR_CANCELLING,
vectorCancellingSlider
vectorCancellingSlider,
EffectType.BIT_CRUSH,
bitCrushSlider
);
}
@ -140,16 +152,25 @@ public class Controller implements Initializable {
tryParse(cameraXTextField.getText()),
tryParse(cameraYTextField.getText()),
tryParse(cameraZTextField.getText())
)));
)));
cameraXTextField.textProperty().addListener(cameraPosUpdate);
cameraYTextField.textProperty().addListener(cameraPosUpdate);
cameraZTextField.textProperty().addListener(cameraPosUpdate);
vectorCancellingCheckBox.selectedProperty().addListener((o, old, checked) ->
updateEffect(EffectType.VECTOR_CANCELLING, checked,
((count, v) -> count % (int) vectorCancellingSlider.getValue() == 0 ? v.scale(-1) : v))
);
InvalidationListener vectorCancellingListener = e ->
updateEffect(EffectType.VECTOR_CANCELLING, vectorCancellingCheckBox.isSelected(),
EventFactory.vectorCancelling((int) vectorCancellingSlider.getValue()));
InvalidationListener bitCrushListener = e ->
updateEffect(EffectType.BIT_CRUSH, bitCrushCheckBox.isSelected(),
EventFactory.bitCrush(bitCrushSlider.getValue()));
vectorCancellingSlider.valueProperty().addListener(vectorCancellingListener);
vectorCancellingCheckBox.selectedProperty().addListener(vectorCancellingListener);
bitCrushSlider.valueProperty().addListener(bitCrushListener);
bitCrushCheckBox.selectedProperty().addListener(bitCrushListener);
chooseFileButton.setOnAction(e -> {
File file = fileChooser.showOpenDialog(stage);
@ -163,7 +184,10 @@ public class Controller implements Initializable {
}
private void setFocalLength(double focalLength) {
producer.setFrameSettings(new ObjFrameSettings(focalLength));
Vector3 pos = (Vector3) producer.setFrameSettings(new ObjFrameSettings(focalLength));
cameraXTextField.setText(String.valueOf(pos.getX()));
cameraYTextField.setText(String.valueOf(pos.getY()));
cameraZTextField.setText(String.valueOf(pos.getZ()));
}
private double tryParse(String value) {

Wyświetl plik

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

Wyświetl plik

@ -29,7 +29,7 @@ public class ObjFrameSet implements FrameSet<List<Shape>> {
}
@Override
public void setFrameSettings(Object settings) {
public Object setFrameSettings(Object settings) {
if (settings instanceof ObjFrameSettings obj) {
Double focalLength = obj.focalLength();
Vector3 cameraPos = obj.cameraPos();
@ -44,5 +44,7 @@ public class ObjFrameSet implements FrameSet<List<Shape>> {
camera.setPos(cameraPos);
}
}
return camera.getPos();
}
}

Wyświetl plik

@ -40,7 +40,9 @@ public abstract class Shape implements FrameSet<List<Shape>> {
}
@Override
public void setFrameSettings(Object settings) {}
public Object setFrameSettings(Object settings) {
return null;
}
/* SHAPE HELPER FUNCTIONS */

Wyświetl plik

@ -18,6 +18,7 @@ public class ShapeFrameSet implements FrameSet<List<Shape>> {
}
@Override
public void setFrameSettings(Object settings) {
public Object setFrameSettings(Object settings) {
return null;
}
}

Wyświetl plik

@ -25,13 +25,13 @@
<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" />
<Label fx:id="rotateSpeedLabel" layoutX="316.0" layoutY="77.0" maxWidth="40.0" text="0" />
<Slider fx:id="translationSpeedSlider" layoutX="116.0" layoutY="105.0" max="10.0" prefHeight="14.0" prefWidth="198.0" value="1.0" />
<Label layoutX="14.0" layoutY="103.0" text="Translation speed" />
<Label fx:id="translationSpeedLabel" layoutX="316.0" layoutY="103.0" text="1" />
<Label fx:id="translationSpeedLabel" layoutX="316.0" layoutY="103.0" maxWidth="40.0" text="1" />
<Slider fx:id="scaleSlider" layoutX="116.0" layoutY="130.0" max="10.0" prefHeight="14.0" prefWidth="198.0" value="1.0" />
<Label layoutX="80.0" layoutY="128.0" text="Scale" />
<Label fx:id="scaleLabel" layoutX="316.0" layoutY="128.0" text="1" />
<Label fx:id="scaleLabel" layoutX="316.0" layoutY="128.0" maxWidth="40.0" text="1" />
<Label layoutX="70.0" layoutY="50.0" text="Weight" />
<TextField fx:id="translationXTextField" layoutX="136.0" layoutY="13.0" prefHeight="26.0" prefWidth="70.0" text="0" />
<Label layoutX="51.0" layoutY="18.0" text="Translation" />
@ -39,7 +39,7 @@
<Label layoutX="217.0" layoutY="18.0" text="y :" />
<TextField fx:id="translationYTextField" layoutX="234.0" layoutY="13.0" prefHeight="26.0" prefWidth="70.0" text="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" maxWidth="40.0" text="100" />
</AnchorPane>
<TitledPane animated="false" collapsible="false" prefHeight="169.0" prefWidth="385.0" text="Effects" SplitPane.resizableWithParent="false">
<content>
@ -47,6 +47,8 @@
<children>
<CheckBox fx:id="vectorCancellingCheckBox" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" text="Vector cancelling" />
<Slider fx:id="vectorCancellingSlider" blockIncrement="1.0" disable="true" layoutX="141.0" layoutY="16.0" majorTickUnit="1.0" max="10.0" min="2.0" minorTickCount="0" prefHeight="33.0" prefWidth="198.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" value="2.0" />
<CheckBox fx:id="bitCrushCheckBox" layoutX="14.0" layoutY="52.0" mnemonicParsing="false" text="Bit crush" />
<Slider fx:id="bitCrushSlider" blockIncrement="1.0" disable="true" layoutX="141.0" layoutY="55.0" majorTickUnit="0.5" max="3.0" minorTickCount="0" prefHeight="33.0" prefWidth="198.0" showTickLabels="true" showTickMarks="true" value="2.0" />
</children>
</AnchorPane>
</content>
@ -56,13 +58,13 @@
<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" />
<TextField fx:id="cameraXTextField" layoutX="134.0" layoutY="39.0" prefHeight="26.0" prefWidth="38.0" text="0" />
<TextField fx:id="cameraXTextField" layoutX="134.0" layoutY="39.0" prefHeight="26.0" prefWidth="58.0" text="0" />
<Label layoutX="44.0" layoutY="44.0" text="Camera pos" />
<Label layoutX="118.0" layoutY="44.0" text="x :" />
<Label layoutX="180.0" layoutY="43.0" text="y :" />
<TextField fx:id="cameraYTextField" layoutX="199.0" layoutY="39.0" prefHeight="26.0" prefWidth="38.0" text="0" />
<Label layoutX="244.0" layoutY="43.0" text="z :" />
<TextField fx:id="cameraZTextField" layoutX="263.0" layoutY="39.0" prefHeight="26.0" prefWidth="38.0" text="0" />
<Label layoutX="199.0" layoutY="43.0" text="y :" />
<TextField fx:id="cameraYTextField" layoutX="218.0" layoutY="39.0" prefHeight="26.0" prefWidth="58.0" text="0" />
<Label layoutX="283.0" layoutY="43.0" text="z :" />
<TextField fx:id="cameraZTextField" layoutX="302.0" layoutY="39.0" prefHeight="26.0" prefWidth="58.0" text="0" />
</AnchorPane>
</TitledPane>
</SplitPane>