Implement working basic UI that controls focal length

pull/35/head
James Ball 2020-11-22 21:07:48 +00:00
rodzic e358df1c34
commit be845393cf
11 zmienionych plików z 194 dodań i 25 usunięć

Wyświetl plik

@ -31,7 +31,7 @@ public class AudioClient {
// example:
// osci-render models/cube.obj 3
public static void main(String[] programArgs)
throws IOException, ParserConfigurationException, SAXException, InterruptedException {
throws IOException, ParserConfigurationException, SAXException {
// TODO: Calculate weight of lines using depth.
// Reduce weight of lines drawn multiple times.
// Find intersections of lines to (possibly) improve line cleanup.

Wyświetl plik

@ -10,6 +10,7 @@ import com.xtaudio.xt.XtService;
import com.xtaudio.xt.XtSetup;
import com.xtaudio.xt.XtStream;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import shapes.Shape;
import shapes.Vector2;
@ -18,7 +19,7 @@ import java.util.List;
public class AudioPlayer implements Runnable {
private final XtFormat FORMAT;
private final ArrayBlockingQueue<List<Shape>> frameQueue;
private final BlockingQueue<List<Shape>> frameQueue;
private List<Shape> frame;
private int currentShape = 0;
@ -34,7 +35,7 @@ public class AudioPlayer implements Runnable {
private volatile boolean stopped;
public AudioPlayer(int sampleRate, ArrayBlockingQueue<List<Shape>> frameQueue) {
public AudioPlayer(int sampleRate, BlockingQueue<List<Shape>> frameQueue) {
this.FORMAT = new XtFormat(new XtMix(sampleRate, XtSample.FLOAT32), 0, 0, 2, 0);
this.frameQueue = frameQueue;
}

Wyświetl plik

@ -0,0 +1,63 @@
package audio;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import parser.FileParser;
import parser.ObjParser;
import parser.TextParser;
import parser.svg.SvgParser;
import shapes.Shape;
public class FrameProducer implements Runnable {
private static final String DEFAULT_FILE = "models/cube.obj";
private final BlockingQueue<List<Shape>> frameQueue;
private ObjParser objParser;
private SvgParser svgParser;
private TextParser textParser;
private FileParser parser;
public FrameProducer(BlockingQueue<List<Shape>> frameQueue)
throws ParserConfigurationException, SAXException, IOException {
this.frameQueue = frameQueue;
setParser(DEFAULT_FILE);
}
@Override
public void run() {
while (true) {
try {
frameQueue.put(parser.nextFrame());
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("Frame missed.");
}
}
}
public void setFocalLength(float focalLength) {
objParser.setFocalLength(focalLength);
}
public void setParser(String filePath)
throws IOException, ParserConfigurationException, SAXException {
if (filePath.matches(".*\\.obj")) {
objParser = new ObjParser(filePath, 1);
parser = objParser;
} else if (filePath.matches(".*\\.svg")) {
svgParser = new SvgParser(filePath);
parser = svgParser;
} else if (filePath.matches(".*\\.txt")) {
textParser = new TextParser(filePath);
parser = textParser;
} else {
throw new IllegalArgumentException(
"Provided file extension in file " + filePath + " not supported.");
}
}
}

Wyświetl plik

@ -20,7 +20,7 @@ public class Camera {
private static final int SAMPLE_RENDER_SAMPLES = 50;
private static final double EPSILON = 0.001;
private final double focalLength;
private double focalLength;
private Vector3 pos;
@ -99,9 +99,11 @@ public class Camera {
return new Vector2();
}
double oldFocalLength = focalLength;
return new Vector2(
vertex.getX() * focalLength / (vertex.getZ() - pos.getZ()) + pos.getX(),
vertex.getY() * focalLength / (vertex.getZ() - pos.getZ()) + pos.getY()
vertex.getX() * oldFocalLength / (vertex.getZ() - pos.getZ()) + pos.getX(),
vertex.getY() * oldFocalLength / (vertex.getZ() - pos.getZ()) + pos.getY()
);
}
@ -117,4 +119,8 @@ public class Camera {
return lines;
}
public void setFocalLength(float focalLength) {
this.focalLength = focalLength;
}
}

Wyświetl plik

@ -1,22 +1,76 @@
package gui;
import audio.AudioPlayer;
import audio.FrameProducer;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Slider;
import javafx.scene.layout.AnchorPane;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathEvaluationResult;
import org.xml.sax.SAXException;
import parser.FileParser;
import parser.ObjParser;
import parser.TextParser;
import parser.svg.SvgParser;
import shapes.Shape;
import shapes.Vector2;
public class Controller implements Initializable {
private static final int BUFFER_SIZE = 20;
private static final int SAMPLE_RATE = 192000;
private final FileChooser fileChooser = new FileChooser();
private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
private final AudioPlayer player = new AudioPlayer(SAMPLE_RATE, frameQueue);
/* Default parser. */
private final FrameProducer producer = new FrameProducer(frameQueue);
private Stage stage;
@FXML
private Button btnBrowse;
@FXML
private Text sliderOutput;
@FXML
private Slider slider;
public Controller() throws IOException, ParserConfigurationException, SAXException {
}
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
slider.valueProperty().addListener(
(source, oldValue, newValue) -> sliderOutput.setText(String.valueOf(slider.getValue())));
slider.valueProperty().addListener((source, oldValue, newValue) -> {
sliderOutput.setText(String.valueOf(slider.getValue()));
producer.setFocalLength((float) slider.getValue());
});
btnBrowse.setOnAction(e -> {
File file = fileChooser.showOpenDialog(stage);
try {
producer.setParser(file.getAbsolutePath());
} catch (IOException | ParserConfigurationException | SAXException ioException) {
ioException.printStackTrace();
}
});
new Thread(producer).start();
new Thread(new AudioPlayer(SAMPLE_RATE, frameQueue)).start();
}
public void setStage(Stage stage) {
this.stage = stage;
}
}

Wyświetl plik

@ -1,6 +1,7 @@
package gui;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
@ -10,10 +11,22 @@ public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("osci-render.fxml"));
FXMLLoader loader = new FXMLLoader(getClass().getResource("osci-render.fxml"));
Parent root = loader.load();
Controller controller = loader.getController();
controller.setStage(primaryStage);
primaryStage.setTitle("osci-render");
primaryStage.setScene(new Scene(root));
controller.setStage(primaryStage);
primaryStage.show();
primaryStage.setOnCloseRequest(t -> {
Platform.exit();
System.exit(0);
});
}
public static void main(String[] args) {

Wyświetl plik

@ -8,8 +8,9 @@
<children>
<AnchorPane prefHeight="400.0" prefWidth="400.0">
<children>
<Slider fx:id="slider" layoutX="44.0" layoutY="54.0" />
<Text fx:id="sliderOutput" layoutX="109.0" layoutY="39.0" strokeType="OUTSIDE" strokeWidth="0.0" text="0" />
<Slider fx:id="slider" blockIncrement="2.0" layoutX="45.0" layoutY="238.0" max="2.0" min="1.0E-5" prefHeight="14.0" prefWidth="313.0" />
<Text fx:id="sliderOutput" layoutX="196.0" layoutY="219.0" strokeType="OUTSIDE" strokeWidth="0.0" text="0" />
<Button fx:id="btnBrowse" layoutX="23.0" layoutY="22.0" mnemonicParsing="false" prefHeight="26.0" prefWidth="119.0" text="Browse" />
</children>
</AnchorPane>
</children>

Wyświetl plik

@ -25,4 +25,5 @@ public abstract class FileParser {
throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException;
public abstract List<Shape> nextFrame();
public abstract String getFilePath();
}

Wyświetl plik

@ -4,36 +4,38 @@ import engine.Camera;
import engine.Vector3;
import engine.WorldObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import shapes.Shape;
public class ObjParser extends FileParser {
private static double OBJ_ROTATE_SPEED = Math.PI / 1000;
private List<List<Shape>> shapes;
private static final float DEFAULT_ROTATE_SPEED = 3;
private final Vector3 cameraPos;
private final Vector3 rotation;
private final double focalLength;
private final boolean isDefaultPosition;
private final String filePath;
private WorldObject object;
private Camera camera;
private double focalLength;
public ObjParser(String path, float rotateSpeed, float cameraX, float cameraY, float cameraZ,
float focalLength, boolean isDefaultPosition) throws IOException {
ObjParser.OBJ_ROTATE_SPEED *= rotateSpeed;
rotateSpeed *= Math.PI / 1000;
checkFileExtension(path);
this.shapes = new ArrayList<>();
this.filePath = path;
this.cameraPos = new Vector3(cameraX, cameraY, cameraZ);
this.isDefaultPosition = isDefaultPosition;
this.focalLength = focalLength;
this.rotation = new Vector3(0, OBJ_ROTATE_SPEED, OBJ_ROTATE_SPEED);
this.rotation = new Vector3(0, rotateSpeed, rotateSpeed);
parseFile(path);
}
public ObjParser(String path, float focalLength) throws IOException {
this(path, DEFAULT_ROTATE_SPEED, 0, 0, 0, focalLength, true);
}
@Override
protected String getFileExtension() {
return "obj";
@ -43,8 +45,7 @@ public class ObjParser extends FileParser {
protected void parseFile(String path) throws IllegalArgumentException, IOException {
object = new WorldObject(path);
camera = new Camera(focalLength, cameraPos);
// If camera position arguments haven't been specified, automatically work out the position of
// the camera based on the size of the object in the camera's view.
if (isDefaultPosition) {
camera.findZPos(object);
}
@ -55,4 +56,18 @@ public class ObjParser extends FileParser {
object.rotate(rotation);
return camera.draw(object);
}
@Override
public String getFilePath() {
return filePath;
}
// If camera position arguments haven't been specified, automatically work out the position of
// the camera based on the size of the object in the camera's view.
public void setFocalLength(float focalLength) {
camera.setFocalLength(focalLength);
if (isDefaultPosition) {
camera.findZPos(object);
}
}
}

Wyświetl plik

@ -22,11 +22,14 @@ public class TextParser extends FileParser {
private final Map<Character, List<Shape>> charToShape;
private final List<String> text;
private final String filePath;
private List<Shape> shapes;
public TextParser(String path, String font)
throws IOException, SAXException, ParserConfigurationException {
checkFileExtension(path);
this.filePath = path;
this.charToShape = new HashMap<>();
this.shapes = new ArrayList<>();
this.text = Files.readAllLines(Paths.get(path), Charset.defaultCharset());
@ -40,7 +43,7 @@ public class TextParser extends FileParser {
@Override
protected String getFileExtension() {
return ".txt";
return "txt";
}
@Override
@ -81,4 +84,9 @@ public class TextParser extends FileParser {
public List<Shape> nextFrame() {
return shapes;
}
@Override
public String getFilePath() {
return filePath;
}
}

Wyświetl plik

@ -27,15 +27,17 @@ public class SvgParser extends FileParser {
private final Map<Character, Function<List<Float>, List<Shape>>> commandMap;
private final SvgState state;
private final String filePath;
private List<Shape> shapes;
private Document svg;
public SvgParser(String path) throws IOException, SAXException, ParserConfigurationException {
checkFileExtension(path);
shapes = new ArrayList<>();
state = new SvgState();
commandMap = new HashMap<>();
this.filePath = path;
this.shapes = new ArrayList<>();
this.state = new SvgState();
this.commandMap = new HashMap<>();
initialiseCommandMap();
parseFile(path);
}
@ -198,4 +200,9 @@ public class SvgParser extends FileParser {
public List<Shape> nextFrame() {
return shapes;
}
@Override
public String getFilePath() {
return filePath;
}
}