kopia lustrzana https://github.com/jameshball/osci-render
Implement working basic UI that controls focal length
rodzic
e358df1c34
commit
be845393cf
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -25,4 +25,5 @@ public abstract class FileParser {
|
|||
throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException;
|
||||
|
||||
public abstract List<Shape> nextFrame();
|
||||
public abstract String getFilePath();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue