diff --git a/blender/plugin.py b/blender/plugin.py
new file mode 100644
index 0000000..e8ec548
--- /dev/null
+++ b/blender/plugin.py
@@ -0,0 +1,62 @@
+import bpy
+import bmesh
+import socket
+import json
+
+HOST = "localhost"
+PORT = 51677
+
+# Persistent global storage for knowing which meshes
+# have already been sent to osci-render
+bpy.context.scene.collection["osci_render"] = {}
+col = bpy.context.scene.collection["osci_render"]
+col["seen_objs"] = {}
+
+camera = bpy.context.scene.camera
+
+
+def my_osci_render_func(scene):
+ engine_info = {"objects": []}
+
+ for obj in bpy.data.objects:
+ if obj.type == 'MESH':
+ object_info = {"name": obj.name}
+ if obj.name not in col["seen_objs"]:
+ col["seen_objs"][obj.name] = 1
+ print("new object! ", obj.name)
+
+ mesh = bmesh.new()
+ mesh.from_mesh(obj.data)
+
+ object_info["vertices"] = []
+ # If there are bugs, the vertices here might not match up with the vert.index in edges
+ for vert in mesh.verts:
+ object_info["vertices"].append({
+ "x": vert.co[0],
+ "y": vert.co[1],
+ "z": vert.co[2],
+ })
+
+ object_info["edges"] = []
+ for edge in mesh.edges:
+ for vert in edge.verts:
+ object_info["edges"].append(vert.index)
+
+ camera_space = camera.matrix_world.inverted() @ obj.matrix_world
+ object_info["matrix"] = []
+ for i in range(4):
+ for j in range(4):
+ object_info["matrix"].append(camera_space[i][j])
+
+ engine_info["objects"].append(object_info)
+
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.connect((HOST, PORT))
+
+ sock.sendall(json.dumps(engine_info, separators=(',', ':')).encode('utf-8'))
+ sock.close()
+
+
+bpy.app.handlers.frame_change_pre.clear()
+bpy.app.handlers.frame_change_pre.append(my_osci_render_func)
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index b38756e..ca2447b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -170,6 +170,12 @@
aparapi
3.0.0
+
+
+ com.google.code.gson
+ gson
+ 2.9.0
+
diff --git a/src/main/java/sh/ball/engine/CameraDrawKernel.java b/src/main/java/sh/ball/engine/CameraDrawKernel.java
index cec03fd..f9abfe5 100644
--- a/src/main/java/sh/ball/engine/CameraDrawKernel.java
+++ b/src/main/java/sh/ball/engine/CameraDrawKernel.java
@@ -8,9 +8,7 @@ import sh.ball.shapes.Shape;
import sh.ball.shapes.Vector2;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.ThreadLocalRandom;
public class CameraDrawKernel extends Kernel {
diff --git a/src/main/java/sh/ball/engine/ObjectServer.java b/src/main/java/sh/ball/engine/ObjectServer.java
new file mode 100644
index 0000000..681f7fe
--- /dev/null
+++ b/src/main/java/sh/ball/engine/ObjectServer.java
@@ -0,0 +1,65 @@
+package sh.ball.engine;
+
+import com.google.gson.Gson;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Arrays;
+
+public class ObjectServer implements Runnable {
+
+ private static final int PORT = 51677;
+ private final Gson gson = new Gson();
+
+ @Override
+ public void run() {
+ try {
+ ServerSocket Server = new ServerSocket(PORT);
+
+ while (true) {
+ System.out.println("Waiting for connection");
+ Socket socket = Server.accept();
+ BufferedReader clientReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ String json = clientReader.readLine();
+ System.out.println(json);
+ EngineInfo info = gson.fromJson(json, EngineInfo.class);
+ System.out.println(info);
+ socket.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static class EngineInfo {
+ private ObjectInfo[] objects;
+
+ @Override
+ public String toString() {
+ return "EngineInfo{" +
+ "objects=" + Arrays.toString(objects) +
+ '}';
+ }
+ }
+
+ private static class ObjectInfo {
+ private String name;
+ private Vector3[] vertices;
+ private int[] edges;
+ // Camera space matrix
+ private float[] matrix;
+
+ @Override
+ public String toString() {
+ return "ObjectInfo{" +
+ "name='" + name + '\'' +
+ ", vertices=" + Arrays.toString(vertices) +
+ ", edges=" + Arrays.toString(edges) +
+ ", matrix=" + Arrays.toString(matrix) +
+ '}';
+ }
+ }
+}
diff --git a/src/main/java/sh/ball/engine/WorldObject.java b/src/main/java/sh/ball/engine/WorldObject.java
index c64b465..b92968e 100644
--- a/src/main/java/sh/ball/engine/WorldObject.java
+++ b/src/main/java/sh/ball/engine/WorldObject.java
@@ -24,6 +24,15 @@ public class WorldObject {
private Vector3 rotation;
private boolean hideEdges = false;
+ private WorldObject(Vector3[] vertices, int[] edgeIndices) {
+ objVertices = Arrays.stream(vertices).toList();
+ Set edges = new HashSet<>();
+ for (int i = 0; i < edgeIndices.length; i += 2) {
+ edges.add(new Line3D(vertices[i], vertices[i + 1]));
+ }
+ getDrawPath(edges);
+ }
+
private WorldObject(List objVertices, List> vertexPath, Vector3 position,
Vector3 rotation) {
this.objVertices = objVertices;
diff --git a/src/main/java/sh/ball/gui/controller/MainController.java b/src/main/java/sh/ball/gui/controller/MainController.java
index a772b2a..906fcba 100644
--- a/src/main/java/sh/ball/gui/controller/MainController.java
+++ b/src/main/java/sh/ball/gui/controller/MainController.java
@@ -48,6 +48,7 @@ import sh.ball.audio.engine.AudioInputListener;
import sh.ball.audio.engine.JavaAudioInput;
import sh.ball.audio.midi.MidiListener;
import sh.ball.audio.midi.MidiNote;
+import sh.ball.engine.ObjectServer;
import sh.ball.gui.Gui;
import sh.ball.parser.obj.ObjFrameSettings;
import sh.ball.parser.obj.ObjParser;
@@ -450,6 +451,8 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
}
}
}
+
+ new Thread(new ObjectServer()).start();
}
// used when a file is chosen so that the same folder is reopened when a