kopia lustrzana https://github.com/jameshball/osci-render
Allow x, y, and z values to be transformed using the 3D depth effect
rodzic
6553e6391c
commit
9194209a66
|
@ -1,17 +1,27 @@
|
||||||
package sh.ball.audio.effect;
|
package sh.ball.audio.effect;
|
||||||
|
|
||||||
|
import org.luaj.vm2.LuaValue;
|
||||||
import sh.ball.engine.Vector3;
|
import sh.ball.engine.Vector3;
|
||||||
|
import sh.ball.parser.lua.LuaExecutor;
|
||||||
import sh.ball.shapes.Vector2;
|
import sh.ball.shapes.Vector2;
|
||||||
|
|
||||||
|
import javax.xml.transform.Result;
|
||||||
|
|
||||||
// 3D rotation effect
|
// 3D rotation effect
|
||||||
public class PerspectiveEffect implements SettableEffect {
|
public class PerspectiveEffect implements SettableEffect {
|
||||||
|
|
||||||
|
private final LuaExecutor executor;
|
||||||
|
|
||||||
private double zPos = 1.0;
|
private double zPos = 1.0;
|
||||||
private Vector3 baseRotation = new Vector3(Math.PI, Math.PI, 0);
|
private Vector3 baseRotation = new Vector3(Math.PI, Math.PI, 0);
|
||||||
private Vector3 currentRotation = new Vector3();
|
private Vector3 currentRotation = new Vector3();
|
||||||
private double rotateSpeed = 0.0;
|
private double rotateSpeed = 0.0;
|
||||||
private double effectScale = 1.0;
|
private double effectScale = 1.0;
|
||||||
|
|
||||||
|
public PerspectiveEffect(LuaExecutor executor) {
|
||||||
|
this.executor = executor;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vector2 apply(int count, Vector2 vector) {
|
public Vector2 apply(int count, Vector2 vector) {
|
||||||
currentRotation = currentRotation.add(baseRotation.scale(rotateSpeed));
|
currentRotation = currentRotation.add(baseRotation.scale(rotateSpeed));
|
||||||
|
@ -19,10 +29,23 @@ public class PerspectiveEffect implements SettableEffect {
|
||||||
Vector3 vertex = new Vector3(vector.x, vector.y, 0.0);
|
Vector3 vertex = new Vector3(vector.x, vector.y, 0.0);
|
||||||
vertex = vertex.rotate(baseRotation.add(currentRotation));
|
vertex = vertex.rotate(baseRotation.add(currentRotation));
|
||||||
|
|
||||||
|
executor.setVariable("x", vertex.x);
|
||||||
|
executor.setVariable("y", vertex.y);
|
||||||
|
executor.setVariable("z", -zPos);
|
||||||
|
double x = vertex.x;
|
||||||
|
double y = vertex.y;
|
||||||
|
double z = -zPos;
|
||||||
|
try {
|
||||||
|
LuaValue result = executor.execute();
|
||||||
|
x = result.get(1).checkdouble();
|
||||||
|
y = result.get(2).checkdouble();
|
||||||
|
z = result.get(3).checkdouble();
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
double focalLength = 1.0;
|
double focalLength = 1.0;
|
||||||
return new Vector2(
|
return new Vector2(
|
||||||
(1 - effectScale) * vector.x + effectScale * (vertex.x * focalLength / (vertex.z - zPos)),
|
(1 - effectScale) * vector.x + effectScale * (x * focalLength / z),
|
||||||
(1 - effectScale) * vector.y + effectScale * (vertex.y * focalLength / (vertex.z - zPos))
|
(1 - effectScale) * vector.y + effectScale * (y * focalLength / z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package sh.ball.audio.engine;
|
package sh.ball.audio.engine;
|
||||||
|
|
||||||
import com.sun.javafx.PlatformUtil;
|
|
||||||
import sh.ball.shapes.Vector2;
|
import sh.ball.shapes.Vector2;
|
||||||
import xt.audio.*;
|
import xt.audio.*;
|
||||||
|
|
||||||
|
@ -237,13 +236,7 @@ public class XtAudioEngine implements AudioEngine {
|
||||||
|
|
||||||
// connects to an XtAudio XtService in order of lowest latency to highest latency
|
// connects to an XtAudio XtService in order of lowest latency to highest latency
|
||||||
private XtService getService(XtPlatform platform) {
|
private XtService getService(XtPlatform platform) {
|
||||||
XtService service = null;
|
XtService service = platform.getService(platform.setupToSystem(Enums.XtSetup.SYSTEM_AUDIO));
|
||||||
if ((PlatformUtil.isLinux() || PlatformUtil.isUnix()) && !PlatformUtil.isMac()) {
|
|
||||||
service = platform.getService(Enums.XtSystem.JACK);
|
|
||||||
}
|
|
||||||
if (service == null) {
|
|
||||||
service = platform.getService(platform.setupToSystem(Enums.XtSetup.SYSTEM_AUDIO));
|
|
||||||
}
|
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
service = platform.getService(platform.setupToSystem(Enums.XtSetup.PRO_AUDIO));
|
service = platform.getService(platform.setupToSystem(Enums.XtSetup.PRO_AUDIO));
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import java.nio.file.Path;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
|
|
||||||
public class Gui extends Application {
|
public class Gui extends Application {
|
||||||
|
@ -40,12 +41,11 @@ public class Gui extends Application {
|
||||||
public static String LOG_DIR = "./logs/";
|
public static String LOG_DIR = "./logs/";
|
||||||
public static final Logger logger = Logger.getLogger(Gui.class.getName());
|
public static final Logger logger = Logger.getLogger(Gui.class.getName());
|
||||||
|
|
||||||
public static ProjectSelectController projectSelectController;
|
|
||||||
public static ShapeAudioPlayer audioPlayer;
|
public static ShapeAudioPlayer audioPlayer;
|
||||||
public static AudioDevice defaultDevice;
|
public static AudioDevice defaultDevice;
|
||||||
public static CodeEditor editor;
|
|
||||||
public static Stage editorStage;
|
private static CodeEditor editor;
|
||||||
public static Scene editorScene;
|
private static Stage editorStage;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
|
@ -79,13 +79,11 @@ public class Gui extends Application {
|
||||||
new Thread(midiCommunicator).start();
|
new Thread(midiCommunicator).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stage stage;
|
|
||||||
private Scene scene;
|
private Scene scene;
|
||||||
private Parent root;
|
private Parent root;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws Exception {
|
public void start(Stage stage) throws Exception {
|
||||||
this.stage = stage;
|
|
||||||
System.setProperty("prism.lcdtext", "false");
|
System.setProperty("prism.lcdtext", "false");
|
||||||
System.setProperty("org.luaj.luajc", "true");
|
System.setProperty("org.luaj.luajc", "true");
|
||||||
|
|
||||||
|
@ -93,7 +91,7 @@ public class Gui extends Application {
|
||||||
|
|
||||||
FXMLLoader projectSelectLoader = new FXMLLoader(getClass().getResource("/fxml/projectSelect.fxml"));
|
FXMLLoader projectSelectLoader = new FXMLLoader(getClass().getResource("/fxml/projectSelect.fxml"));
|
||||||
Parent projectSelectRoot = projectSelectLoader.load();
|
Parent projectSelectRoot = projectSelectLoader.load();
|
||||||
projectSelectController = projectSelectLoader.getController();
|
ProjectSelectController projectSelectController = projectSelectLoader.getController();
|
||||||
projectSelectController.setOpenBrowser(url -> getHostServices().showDocument(url));
|
projectSelectController.setOpenBrowser(url -> getHostServices().showDocument(url));
|
||||||
|
|
||||||
stage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/icons/icon.png"))));
|
stage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResourceAsStream("/icons/icon.png"))));
|
||||||
|
@ -166,12 +164,11 @@ public class Gui extends Application {
|
||||||
editor = new CodeEditor();
|
editor = new CodeEditor();
|
||||||
editor.initialize();
|
editor.initialize();
|
||||||
editorStage = new Stage();
|
editorStage = new Stage();
|
||||||
editorScene = new Scene(editor, 900, 600, false, SceneAntialiasing.BALANCED);
|
Scene editorScene = new Scene(editor, 900, 600, false, SceneAntialiasing.BALANCED);
|
||||||
editorStage.setScene(editorScene);
|
editorStage.setScene(editorScene);
|
||||||
editorStage.getIcons().add(new Image(Objects.requireNonNull(Gui.class.getResourceAsStream("/icons/icon.png"))));
|
editorStage.getIcons().add(new Image(Objects.requireNonNull(Gui.class.getResourceAsStream("/icons/icon.png"))));
|
||||||
editor.prefHeightProperty().bind(editorStage.heightProperty());
|
editor.prefHeightProperty().bind(editorStage.heightProperty());
|
||||||
editor.prefWidthProperty().bind(editorStage.widthProperty());
|
editor.prefWidthProperty().bind(editorStage.widthProperty());
|
||||||
editor.setCallback(controller::updateFileData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void launchMainApplication(MainController controller, String projectPath, Boolean muted) throws Exception {
|
public void launchMainApplication(MainController controller, String projectPath, Boolean muted) throws Exception {
|
||||||
|
@ -194,20 +191,12 @@ public class Gui extends Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void launchCodeEditor(String code, String fileName) {
|
public static void launchCodeEditor(String code, String fileName, String mimeType, BiConsumer<byte[], String> callback) {
|
||||||
editor.setCode(code, fileName);
|
editor.setCode(code, fileName);
|
||||||
|
editor.setCallback(callback);
|
||||||
editorStage.show();
|
editorStage.show();
|
||||||
editorStage.setTitle(fileName);
|
editorStage.setTitle(fileName);
|
||||||
|
editor.setMode(mimeType);
|
||||||
if (LuaParser.isLuaFile(fileName)) {
|
|
||||||
editor.setMode("text/x-lua");
|
|
||||||
} else if (ObjParser.isObjFile(fileName)) {
|
|
||||||
editor.setMode("");
|
|
||||||
} else if (SvgParser.isSvgFile(fileName)) {
|
|
||||||
editor.setMode("text/html");
|
|
||||||
} else if (TextParser.isTxtFile(fileName)) {
|
|
||||||
editor.setMode("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void closeCodeEditor() {
|
public static void closeCodeEditor() {
|
||||||
|
|
|
@ -13,11 +13,15 @@ import org.w3c.dom.Element;
|
||||||
import sh.ball.audio.FrequencyAnalyser;
|
import sh.ball.audio.FrequencyAnalyser;
|
||||||
import sh.ball.audio.effect.*;
|
import sh.ball.audio.effect.*;
|
||||||
import sh.ball.audio.engine.AudioDevice;
|
import sh.ball.audio.engine.AudioDevice;
|
||||||
|
import sh.ball.gui.Gui;
|
||||||
import sh.ball.gui.components.EffectComponentGroup;
|
import sh.ball.gui.components.EffectComponentGroup;
|
||||||
|
import sh.ball.parser.lua.LuaExecutor;
|
||||||
|
import sh.ball.parser.lua.LuaParser;
|
||||||
import sh.ball.shapes.Shape;
|
import sh.ball.shapes.Shape;
|
||||||
import sh.ball.shapes.Vector2;
|
import sh.ball.shapes.Vector2;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -29,6 +33,8 @@ public class EffectsController implements Initializable, SubController {
|
||||||
|
|
||||||
private static final int DEFAULT_SAMPLE_RATE = 192000;
|
private static final int DEFAULT_SAMPLE_RATE = 192000;
|
||||||
|
|
||||||
|
private final LuaExecutor executor = new LuaExecutor(LuaExecutor.STANDARD_GLOBALS);
|
||||||
|
|
||||||
private final WobbleEffect wobbleEffect;
|
private final WobbleEffect wobbleEffect;
|
||||||
private final PerspectiveEffect perspectiveEffect;
|
private final PerspectiveEffect perspectiveEffect;
|
||||||
private final TranslateEffect translateEffect;
|
private final TranslateEffect translateEffect;
|
||||||
|
@ -88,10 +94,12 @@ public class EffectsController implements Initializable, SubController {
|
||||||
private Button resetRotationButton;
|
private Button resetRotationButton;
|
||||||
@FXML
|
@FXML
|
||||||
private Button resetPerspectiveRotationButton;
|
private Button resetPerspectiveRotationButton;
|
||||||
|
@FXML
|
||||||
|
private Button depthFunctionButton;
|
||||||
|
|
||||||
public EffectsController() {
|
public EffectsController() {
|
||||||
this.wobbleEffect = new WobbleEffect(DEFAULT_SAMPLE_RATE);
|
this.wobbleEffect = new WobbleEffect(DEFAULT_SAMPLE_RATE);
|
||||||
this.perspectiveEffect = new PerspectiveEffect();
|
this.perspectiveEffect = new PerspectiveEffect(executor);
|
||||||
this.translateEffect = new TranslateEffect(DEFAULT_SAMPLE_RATE, 1, new Vector2());
|
this.translateEffect = new TranslateEffect(DEFAULT_SAMPLE_RATE, 1, new Vector2());
|
||||||
this.rotateEffect = new RotateEffect(DEFAULT_SAMPLE_RATE);
|
this.rotateEffect = new RotateEffect(DEFAULT_SAMPLE_RATE);
|
||||||
}
|
}
|
||||||
|
@ -237,6 +245,14 @@ public class EffectsController implements Initializable, SubController {
|
||||||
rotateSpeed3D.controller.slider.setValue(0);
|
rotateSpeed3D.controller.slider.setValue(0);
|
||||||
perspectiveEffect.resetRotation();
|
perspectiveEffect.resetRotation();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
String script = "return { x, y, z }";
|
||||||
|
executor.setScript(script);
|
||||||
|
depthFunctionButton.setOnAction(e -> Gui.launchCodeEditor(script, "3D Perspective Effect Depth Function", "text/x-lua", this::updateDepthFunction));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDepthFunction(byte[] fileData, String fileName) {
|
||||||
|
executor.setScript(new String(fileData, StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<EffectComponentGroup> effects() {
|
private List<EffectComponentGroup> effects() {
|
||||||
|
|
|
@ -4,10 +4,15 @@ import javafx.animation.KeyFrame;
|
||||||
import javafx.animation.Timeline;
|
import javafx.animation.Timeline;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.event.Event;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.Menu;
|
import javafx.scene.control.Menu;
|
||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.control.skin.ComboBoxListViewSkin;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.paint.Paint;
|
import javafx.scene.paint.Paint;
|
||||||
import javafx.scene.shape.SVGPath;
|
import javafx.scene.shape.SVGPath;
|
||||||
|
@ -61,6 +66,7 @@ import sh.ball.parser.lua.LuaParser;
|
||||||
import sh.ball.parser.obj.ObjFrameSettings;
|
import sh.ball.parser.obj.ObjFrameSettings;
|
||||||
import sh.ball.parser.obj.ObjParser;
|
import sh.ball.parser.obj.ObjParser;
|
||||||
import sh.ball.parser.ParserFactory;
|
import sh.ball.parser.ParserFactory;
|
||||||
|
import sh.ball.parser.svg.SvgParser;
|
||||||
import sh.ball.parser.txt.FontStyle;
|
import sh.ball.parser.txt.FontStyle;
|
||||||
import sh.ball.shapes.Shape;
|
import sh.ball.shapes.Shape;
|
||||||
import sh.ball.shapes.ShapeFrameSource;
|
import sh.ball.shapes.ShapeFrameSource;
|
||||||
|
@ -142,6 +148,8 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
|
||||||
@FXML
|
@FXML
|
||||||
private MenuItem openProjectMenuItem;
|
private MenuItem openProjectMenuItem;
|
||||||
@FXML
|
@FXML
|
||||||
|
private Menu audioMenu;
|
||||||
|
@FXML
|
||||||
private Menu recentProjectMenu;
|
private Menu recentProjectMenu;
|
||||||
@FXML
|
@FXML
|
||||||
private MenuItem saveProjectMenuItem;
|
private MenuItem saveProjectMenuItem;
|
||||||
|
@ -184,6 +192,8 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
|
||||||
@FXML
|
@FXML
|
||||||
private ComboBox<AudioDevice> deviceComboBox;
|
private ComboBox<AudioDevice> deviceComboBox;
|
||||||
@FXML
|
@FXML
|
||||||
|
private CustomMenuItem audioDeviceMenuItem;
|
||||||
|
@FXML
|
||||||
private Slider brightnessSlider;
|
private Slider brightnessSlider;
|
||||||
@FXML
|
@FXML
|
||||||
private CustomMenuItem recordLengthMenuItem;
|
private CustomMenuItem recordLengthMenuItem;
|
||||||
|
@ -1397,7 +1407,14 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
|
||||||
void openCodeEditor() {
|
void openCodeEditor() {
|
||||||
String code = new String(openFiles.get(currentFrameSource), StandardCharsets.UTF_8);
|
String code = new String(openFiles.get(currentFrameSource), StandardCharsets.UTF_8);
|
||||||
closeCodeEditor();
|
closeCodeEditor();
|
||||||
launchCodeEditor(code, frameSourcePaths.get(currentFrameSource));
|
String name = frameSourcePaths.get(currentFrameSource);
|
||||||
|
String mimeType = "";
|
||||||
|
if (LuaParser.isLuaFile(name)) {
|
||||||
|
mimeType = "text/x-lua";
|
||||||
|
} else if (SvgParser.isSvgFile(name)) {
|
||||||
|
mimeType = "text/html";
|
||||||
|
}
|
||||||
|
launchCodeEditor(code, frameSourcePaths.get(currentFrameSource), mimeType, this::updateFileData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTitle(String message, String projectName) {
|
private void updateTitle(String message, String projectName) {
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
package sh.ball.parser.lua;
|
||||||
|
|
||||||
|
import org.luaj.vm2.*;
|
||||||
|
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||||
|
import org.luaj.vm2.lib.TwoArgFunction;
|
||||||
|
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
||||||
|
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||||
|
|
||||||
|
import javax.script.ScriptException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import static sh.ball.gui.Gui.logger;
|
||||||
|
|
||||||
|
public class LuaExecutor {
|
||||||
|
|
||||||
|
public static final Globals STANDARD_GLOBALS = JsePlatform.standardGlobals();
|
||||||
|
|
||||||
|
static {
|
||||||
|
org.luaj.vm2.luajc.LuaJC.install(STANDARD_GLOBALS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Globals globals;
|
||||||
|
private final Map<LuaString, LuaValue> bindings = new HashMap<>();
|
||||||
|
private final Set<LuaString> programDefinedVariables = new HashSet<>();
|
||||||
|
private LuaFunction lastWorkingFunction;
|
||||||
|
private String lastWorkingTextScript;
|
||||||
|
private LuaFunction function;
|
||||||
|
private String textScript;
|
||||||
|
private long step = 1;
|
||||||
|
|
||||||
|
public LuaExecutor(Globals globals) {
|
||||||
|
this.globals = globals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScript(String script) {
|
||||||
|
LuaFunction f = LuaExecutor.STANDARD_GLOBALS.load(new StringReader(script), "script").checkfunction();
|
||||||
|
setFunction(script, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFunction(String textScript, LuaFunction function) {
|
||||||
|
if (lastWorkingFunction == null) {
|
||||||
|
lastWorkingFunction = function;
|
||||||
|
lastWorkingTextScript = textScript;
|
||||||
|
}
|
||||||
|
this.function = function;
|
||||||
|
this.textScript = textScript;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue execute() {
|
||||||
|
try {
|
||||||
|
boolean updatedFile = false;
|
||||||
|
|
||||||
|
globals.setmetatable(new BindingsMetatable(bindings));
|
||||||
|
bindings.put(LuaValue.valueOf("step"), LuaValue.valueOf((double) step));
|
||||||
|
|
||||||
|
LuaValue result;
|
||||||
|
try {
|
||||||
|
result = (LuaValue) LuaExecutor.eval(function, globals);
|
||||||
|
if (!lastWorkingTextScript.equals(textScript)) {
|
||||||
|
lastWorkingFunction = function;
|
||||||
|
lastWorkingTextScript = textScript;
|
||||||
|
updatedFile = true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.INFO, e.getMessage(), e);
|
||||||
|
result = (LuaValue) LuaExecutor.eval(lastWorkingFunction, globals);
|
||||||
|
}
|
||||||
|
step++;
|
||||||
|
|
||||||
|
if (updatedFile) {
|
||||||
|
// reset variables
|
||||||
|
step = 1;
|
||||||
|
List<LuaString> variablesToRemove = new ArrayList<>();
|
||||||
|
bindings.keySet().forEach(name -> {
|
||||||
|
if (!programDefinedVariables.contains(name)) {
|
||||||
|
variablesToRemove.add(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
variablesToRemove.forEach(bindings::remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.INFO, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LuaValue.NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVariable(String variableName, Object value) {
|
||||||
|
LuaString name = LuaValue.valueOf(variableName);
|
||||||
|
programDefinedVariables.add(name);
|
||||||
|
bindings.put(name, toLua(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetStep() {
|
||||||
|
step = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2007 LuaJ. All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit p ersons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
The below functions have all been modified by James Ball to optimise Lua parsing
|
||||||
|
on machines with poorer performance.
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
static class BindingsMetatable extends LuaTable {
|
||||||
|
|
||||||
|
BindingsMetatable(Map<LuaString, LuaValue> bindings) {
|
||||||
|
this.rawset(LuaValue.INDEX, new TwoArgFunction() {
|
||||||
|
public LuaValue call(LuaValue table, LuaValue key) {
|
||||||
|
LuaValue value = bindings.get(key.checkstring());
|
||||||
|
if (value == null) {
|
||||||
|
return LuaValue.NIL;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.rawset(LuaValue.NEWINDEX, new ThreeArgFunction() {
|
||||||
|
public LuaValue call(LuaValue table, LuaValue key, LuaValue value) {
|
||||||
|
if (value == null || value.type() == LuaValue.TNIL) {
|
||||||
|
bindings.remove(key.checkstring());
|
||||||
|
} else {
|
||||||
|
bindings.put(key.checkstring(), value);
|
||||||
|
}
|
||||||
|
return LuaValue.NONE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static private LuaValue toLua(Object javaValue) {
|
||||||
|
return javaValue == null? LuaValue.NIL:
|
||||||
|
javaValue instanceof LuaValue? (LuaValue) javaValue:
|
||||||
|
CoerceJavaToLua.coerce(javaValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static private Object toJava(LuaValue luajValue) {
|
||||||
|
return switch (luajValue.type()) {
|
||||||
|
case LuaValue.TNIL -> null;
|
||||||
|
case LuaValue.TSTRING -> luajValue.tojstring();
|
||||||
|
case LuaValue.TUSERDATA -> luajValue.checkuserdata(Object.class);
|
||||||
|
case LuaValue.TNUMBER -> luajValue.isinttype() ?
|
||||||
|
(Object) luajValue.toint() :
|
||||||
|
(Object) luajValue.todouble();
|
||||||
|
default -> luajValue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static private Object toJava(Varargs v) {
|
||||||
|
final int n = v.narg();
|
||||||
|
switch (n) {
|
||||||
|
case 0: return null;
|
||||||
|
case 1: return toJava(v.arg1());
|
||||||
|
default:
|
||||||
|
Object[] o = new Object[n];
|
||||||
|
for (int i=0; i<n; ++i)
|
||||||
|
o[i] = toJava(v.arg(i+1));
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static private Object eval(LuaFunction f, Globals g) throws ScriptException {
|
||||||
|
try {
|
||||||
|
f = f.getClass().newInstance();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
throw new ScriptException(e);
|
||||||
|
}
|
||||||
|
f.initupvalue1(g);
|
||||||
|
return toJava(f.invoke(LuaValue.NONE));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,15 @@
|
||||||
package sh.ball.parser.lua;
|
package sh.ball.parser.lua;
|
||||||
|
|
||||||
import org.luaj.vm2.Globals;
|
|
||||||
import org.luaj.vm2.LuaFunction;
|
|
||||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
|
||||||
import sh.ball.audio.FrameSource;
|
import sh.ball.audio.FrameSource;
|
||||||
import sh.ball.parser.FileParser;
|
import sh.ball.parser.FileParser;
|
||||||
import sh.ball.shapes.Vector2;
|
import sh.ball.shapes.Vector2;
|
||||||
|
|
||||||
import javax.script.*;
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class LuaParser extends FileParser<FrameSource<Vector2>> {
|
public class LuaParser extends FileParser<FrameSource<Vector2>> {
|
||||||
|
|
||||||
private static final Globals globals = JsePlatform.standardGlobals();
|
private final LuaSampleSource sampleSource = new LuaSampleSource(LuaExecutor.STANDARD_GLOBALS);
|
||||||
|
|
||||||
static {
|
|
||||||
org.luaj.vm2.luajc.LuaJC.install(globals);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final LuaSampleSource sampleSource = new LuaSampleSource(globals);
|
|
||||||
|
|
||||||
private String script;
|
private String script;
|
||||||
|
|
||||||
|
@ -35,10 +25,7 @@ public class LuaParser extends FileParser<FrameSource<Vector2>> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FrameSource<Vector2> parse() throws Exception {
|
public FrameSource<Vector2> parse() throws Exception {
|
||||||
LuaFunction f = globals.load(new StringReader(script), "script").checkfunction();
|
sampleSource.setScript(script);
|
||||||
|
|
||||||
sampleSource.setFunction(script, f);
|
|
||||||
|
|
||||||
return sampleSource;
|
return sampleSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,69 +18,21 @@ import static sh.ball.gui.Gui.logger;
|
||||||
|
|
||||||
public class LuaSampleSource implements FrameSource<Vector2> {
|
public class LuaSampleSource implements FrameSource<Vector2> {
|
||||||
|
|
||||||
private final Globals globals;
|
private final LuaExecutor executor;
|
||||||
private final Map<LuaString, LuaValue> bindings = new HashMap<>();
|
|
||||||
private final Set<LuaString> programDefinedVariables = new HashSet<>();
|
|
||||||
private LuaFunction lastWorkingFunction;
|
|
||||||
private String lastWorkingTextScript;
|
|
||||||
private LuaFunction function;
|
|
||||||
private String textScript;
|
|
||||||
private boolean active = true;
|
private boolean active = true;
|
||||||
private long step = 1;
|
|
||||||
|
|
||||||
public LuaSampleSource(Globals globals) {
|
public LuaSampleSource(Globals globals) {
|
||||||
this.globals = globals;
|
this.executor = new LuaExecutor(globals);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFunction(String textScript, LuaFunction function) {
|
public void setScript(String textScript) {
|
||||||
if (lastWorkingFunction == null) {
|
executor.setScript(textScript);
|
||||||
lastWorkingFunction = function;
|
|
||||||
lastWorkingTextScript = textScript;
|
|
||||||
}
|
|
||||||
this.function = function;
|
|
||||||
this.textScript = textScript;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vector2 next() {
|
public Vector2 next() {
|
||||||
try {
|
LuaValue result = executor.execute();
|
||||||
boolean updatedFile = false;
|
|
||||||
|
|
||||||
globals.setmetatable(new BindingsMetatable(bindings));
|
|
||||||
bindings.put(LuaValue.valueOf("step"), LuaValue.valueOf((double) step));
|
|
||||||
|
|
||||||
LuaValue result;
|
|
||||||
try {
|
|
||||||
result = (LuaValue) LuaSampleSource.eval(function, globals);
|
|
||||||
if (!lastWorkingTextScript.equals(textScript)) {
|
|
||||||
lastWorkingFunction = function;
|
|
||||||
lastWorkingTextScript = textScript;
|
|
||||||
updatedFile = true;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.INFO, e.getMessage(), e);
|
|
||||||
result = (LuaValue) LuaSampleSource.eval(lastWorkingFunction, globals);
|
|
||||||
}
|
|
||||||
step++;
|
|
||||||
|
|
||||||
if (updatedFile) {
|
|
||||||
// reset variables
|
|
||||||
step = 1;
|
|
||||||
List<LuaString> variablesToRemove = new ArrayList<>();
|
|
||||||
bindings.keySet().forEach(name -> {
|
|
||||||
if (!programDefinedVariables.contains(name)) {
|
|
||||||
variablesToRemove.add(name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
variablesToRemove.forEach(bindings::remove);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Vector2(result.get(1).checkdouble(), result.get(2).checkdouble());
|
return new Vector2(result.get(1).checkdouble(), result.get(2).checkdouble());
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.INFO, e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Vector2();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -107,110 +59,10 @@ public class LuaSampleSource implements FrameSource<Vector2> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVariable(String variableName, Object value) {
|
public void setVariable(String variableName, Object value) {
|
||||||
programDefinedVariables.add(LuaValue.valueOf(variableName));
|
executor.setVariable(variableName, value);
|
||||||
bindings.put(LuaValue.valueOf(variableName), toLua(value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetStep() {
|
public void resetStep() {
|
||||||
step = 1;
|
executor.resetStep();
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2007 LuaJ. All rights reserved.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit p ersons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
------------------------------
|
|
||||||
|
|
||||||
The below functions have all been modified by James Ball to optimise Lua parsing
|
|
||||||
on machines with poorer performance.
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
static class BindingsMetatable extends LuaTable {
|
|
||||||
|
|
||||||
BindingsMetatable(Map<LuaString, LuaValue> bindings) {
|
|
||||||
this.rawset(LuaValue.INDEX, new TwoArgFunction() {
|
|
||||||
public LuaValue call(LuaValue table, LuaValue key) {
|
|
||||||
LuaValue value = bindings.get(key.checkstring());
|
|
||||||
if (value == null) {
|
|
||||||
return LuaValue.NIL;
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.rawset(LuaValue.NEWINDEX, new ThreeArgFunction() {
|
|
||||||
public LuaValue call(LuaValue table, LuaValue key, LuaValue value) {
|
|
||||||
if (value == null || value.type() == LuaValue.TNIL) {
|
|
||||||
bindings.remove(key.checkstring());
|
|
||||||
} else {
|
|
||||||
bindings.put(key.checkstring(), value);
|
|
||||||
}
|
|
||||||
return LuaValue.NONE;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static private LuaValue toLua(Object javaValue) {
|
|
||||||
return javaValue == null? LuaValue.NIL:
|
|
||||||
javaValue instanceof LuaValue? (LuaValue) javaValue:
|
|
||||||
CoerceJavaToLua.coerce(javaValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
static private Object toJava(LuaValue luajValue) {
|
|
||||||
return switch (luajValue.type()) {
|
|
||||||
case LuaValue.TNIL -> null;
|
|
||||||
case LuaValue.TSTRING -> luajValue.tojstring();
|
|
||||||
case LuaValue.TUSERDATA -> luajValue.checkuserdata(Object.class);
|
|
||||||
case LuaValue.TNUMBER -> luajValue.isinttype() ?
|
|
||||||
(Object) luajValue.toint() :
|
|
||||||
(Object) luajValue.todouble();
|
|
||||||
default -> luajValue;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static private Object toJava(Varargs v) {
|
|
||||||
final int n = v.narg();
|
|
||||||
switch (n) {
|
|
||||||
case 0: return null;
|
|
||||||
case 1: return toJava(v.arg1());
|
|
||||||
default:
|
|
||||||
Object[] o = new Object[n];
|
|
||||||
for (int i=0; i<n; ++i)
|
|
||||||
o[i] = toJava(v.arg(i+1));
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static private Object eval(LuaFunction f, Globals g) throws ScriptException {
|
|
||||||
try {
|
|
||||||
f = f.getClass().newInstance();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
|
||||||
throw new ScriptException(e);
|
|
||||||
}
|
|
||||||
f.initupvalue1(g);
|
|
||||||
return toJava(f.invoke(LuaValue.NONE));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,12 @@
|
||||||
</children>
|
</children>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
<EffectComponentGroup fx:id="depthScale" increment="0.005" label="depthScale" majorTickUnit="0.1" max="1.0" min="0.0" name="3D Perspective" type="DEPTH_3D" value="1.0" />
|
<EffectComponentGroup fx:id="depthScale" increment="0.005" label="depthScale" majorTickUnit="0.1" max="1.0" min="0.0" name="3D Perspective" type="DEPTH_3D" value="1.0" />
|
||||||
<EffectComponentGroup fx:id="zPos" alwaysEnabled="true" increment="0.005" label="zPos" max="1.0" name="3D Distance" type="Z_POS_3D" value="0.1" />
|
<AnchorPane prefHeight="34.0" prefWidth="602.0">
|
||||||
|
<children>
|
||||||
|
<Button fx:id="depthFunctionButton" layoutX="232.0" layoutY="1.0" mnemonicParsing="false" text="Modify Depth Function" />
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
<EffectComponentGroup fx:id="zPos" alwaysEnabled="true" increment="0.005" label="zPos" max="1.0" name="3D Distance (z)" type="Z_POS_3D" value="0.1" />
|
||||||
<EffectComponentGroup fx:id="rotateSpeed3D" alwaysEnabled="true" increment="0.005" label="rotateSpeed3d" majorTickUnit="0.2" max="1.0" min="-1.0" name="3D Rotate speed" type="ROTATE_SPEED_3D" value="0.0" />
|
<EffectComponentGroup fx:id="rotateSpeed3D" alwaysEnabled="true" increment="0.005" label="rotateSpeed3d" majorTickUnit="0.2" max="1.0" min="-1.0" name="3D Rotate speed" type="ROTATE_SPEED_3D" value="0.0" />
|
||||||
<EffectComponentGroup fx:id="rotateX" alwaysEnabled="true" increment="0.01" label="imageRotateX" majorTickUnit="0.2" max="1.0" min="-1.0" name="Rotate x" type="ROTATE_X" value="1.0" />
|
<EffectComponentGroup fx:id="rotateX" alwaysEnabled="true" increment="0.01" label="imageRotateX" majorTickUnit="0.2" max="1.0" min="-1.0" name="Rotate x" type="ROTATE_X" value="1.0" />
|
||||||
<EffectComponentGroup fx:id="rotateY" alwaysEnabled="true" increment="0.01" label="imageRotateY" majorTickUnit="0.2" max="1.0" min="-1.0" name="Rotate y" type="ROTATE_Y" value="1.0" />
|
<EffectComponentGroup fx:id="rotateY" alwaysEnabled="true" increment="0.01" label="imageRotateY" majorTickUnit="0.2" max="1.0" min="-1.0" name="Rotate y" type="ROTATE_Y" value="1.0" />
|
||||||
|
|
|
@ -39,11 +39,11 @@
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</items>
|
</items>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Menu mnemonicParsing="false" text="Audio">
|
<Menu fx:id="audioMenu" mnemonicParsing="false" text="Audio">
|
||||||
<items>
|
<items>
|
||||||
<CustomMenuItem hideOnClick="false" mnemonicParsing="false" text="Audio Device">
|
<CustomMenuItem fx:id="audioDeviceMenuItem" hideOnClick="false" mnemonicParsing="false" text="Audio Device">
|
||||||
<content>
|
<content>
|
||||||
<AnchorPane>
|
<AnchorPane focusTraversable="true">
|
||||||
<children>
|
<children>
|
||||||
<ComboBox fx:id="deviceComboBox" prefHeight="26.0" prefWidth="376.0" />
|
<ComboBox fx:id="deviceComboBox" prefHeight="26.0" prefWidth="376.0" />
|
||||||
</children>
|
</children>
|
||||||
|
|
Ładowanie…
Reference in New Issue