2022-04-28 21:16:12 +00:00
|
|
|
bl_info = {
|
|
|
|
"name": "osci-render",
|
|
|
|
"author": "James Ball",
|
2022-04-30 09:18:32 +00:00
|
|
|
"version": (1, 0, 2),
|
2022-04-28 21:16:12 +00:00
|
|
|
"blender": (3, 1, 2),
|
|
|
|
"location": "View3D",
|
2022-04-28 22:53:09 +00:00
|
|
|
"description": "Addon to send gpencil frames over to osci-render",
|
|
|
|
"warning": "Requires a camera and gpencil object",
|
2022-04-28 21:16:12 +00:00
|
|
|
"wiki_url": "https://github.com/jameshball/osci-render",
|
|
|
|
"category": "Development",
|
|
|
|
}
|
|
|
|
|
|
|
|
import bpy
|
|
|
|
import bmesh
|
|
|
|
import socket
|
|
|
|
import json
|
2022-04-30 17:51:56 +00:00
|
|
|
import atexit
|
2022-04-30 09:18:32 +00:00
|
|
|
from bpy.app.handlers import persistent
|
2022-04-28 21:16:12 +00:00
|
|
|
|
|
|
|
HOST = "localhost"
|
|
|
|
PORT = 51677
|
|
|
|
|
|
|
|
sock = None
|
|
|
|
|
|
|
|
|
|
|
|
class OBJECT_PT_osci_render_settings(bpy.types.Panel):
|
|
|
|
bl_idname = "OBJECT_PT_osci_render_settings"
|
|
|
|
bl_label = "osci-render settings"
|
|
|
|
bl_space_type = "PROPERTIES"
|
|
|
|
bl_region_type = "WINDOW"
|
|
|
|
bl_context = "render"
|
|
|
|
|
|
|
|
def draw_header(self, context):
|
|
|
|
layout = self.layout
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
global sock
|
|
|
|
if sock is None:
|
|
|
|
self.layout.operator("render.osci_render_connect", text="Connect to osci-render")
|
|
|
|
else:
|
|
|
|
self.layout.operator("render.osci_render_close", text="Close osci-render connection")
|
|
|
|
|
|
|
|
|
|
|
|
class osci_render_connect(bpy.types.Operator):
|
|
|
|
bl_label = "Connect to osci-render"
|
|
|
|
bl_idname = "render.osci_render_connect"
|
|
|
|
bl_description = "Connect to osci-render"
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
global sock
|
|
|
|
if sock is None:
|
|
|
|
try:
|
|
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
2022-04-30 17:51:56 +00:00
|
|
|
sock.settimeout(1)
|
2022-04-28 21:16:12 +00:00
|
|
|
sock.connect((HOST, PORT))
|
|
|
|
send_scene_to_osci_render(bpy.context.scene)
|
2022-04-30 17:51:56 +00:00
|
|
|
except socket.error as exp:
|
2022-04-28 21:16:12 +00:00
|
|
|
sock = None
|
2022-04-30 17:51:56 +00:00
|
|
|
self.report({"WARNING"}, "Failed to connect to osci-render - make sure it is running first!")
|
|
|
|
return {"CANCELLED"}
|
2022-04-28 21:16:12 +00:00
|
|
|
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
|
|
|
|
class osci_render_close(bpy.types.Operator):
|
|
|
|
bl_label = "Close osci-render connection"
|
2022-04-28 22:53:09 +00:00
|
|
|
bl_idname = "render.osci_render_close"
|
2022-04-28 21:16:12 +00:00
|
|
|
|
|
|
|
def execute(self, context):
|
2022-04-30 17:51:56 +00:00
|
|
|
close_osci_render()
|
2022-04-28 21:16:12 +00:00
|
|
|
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
|
2022-04-30 17:51:56 +00:00
|
|
|
@persistent
|
|
|
|
def close_osci_render():
|
|
|
|
global sock
|
|
|
|
if sock is not None:
|
|
|
|
try:
|
|
|
|
sock.send("CLOSE\n".encode('utf-8'))
|
|
|
|
sock.close()
|
|
|
|
except socket.error as exp:
|
|
|
|
sock = None
|
2022-04-28 21:16:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
def append_matrix(object_info, obj):
|
|
|
|
camera_space = bpy.context.scene.camera.matrix_world.inverted() @ obj.matrix_world
|
|
|
|
object_info["matrix"] = [camera_space[i][j] for i in range(4) for j in range(4)]
|
|
|
|
return object_info
|
|
|
|
|
|
|
|
|
2022-04-30 09:18:32 +00:00
|
|
|
@persistent
|
2022-04-28 21:16:12 +00:00
|
|
|
def send_scene_to_osci_render(scene):
|
2022-04-30 17:51:56 +00:00
|
|
|
global sock
|
2022-04-28 22:53:09 +00:00
|
|
|
engine_info = {"objects": []}
|
2022-04-30 17:51:56 +00:00
|
|
|
|
2022-04-28 21:16:12 +00:00
|
|
|
if sock is not None:
|
|
|
|
for obj in bpy.data.objects:
|
2022-04-28 22:53:09 +00:00
|
|
|
if obj.visible_get() and obj.type == 'GPENCIL':
|
|
|
|
object_info = {"name": obj.name}
|
|
|
|
strokes = obj.data.layers.active.frames.data.active_frame.strokes
|
|
|
|
|
|
|
|
object_info["vertices"] = []
|
|
|
|
for stroke in strokes:
|
|
|
|
object_info["vertices"].append([{
|
|
|
|
"x": vert.co[0],
|
|
|
|
"y": vert.co[1],
|
|
|
|
"z": vert.co[2],
|
|
|
|
} for vert in stroke.points])
|
|
|
|
|
|
|
|
engine_info["objects"].append(append_matrix(object_info, obj))
|
2022-04-30 17:51:56 +00:00
|
|
|
|
2022-04-28 21:16:12 +00:00
|
|
|
|
2022-04-28 22:53:09 +00:00
|
|
|
engine_info["focalLength"] = -0.05 * bpy.data.cameras[0].lens
|
2022-04-28 21:16:12 +00:00
|
|
|
|
2022-04-28 22:53:09 +00:00
|
|
|
json_str = json.dumps(engine_info, separators=(',', ':')) + '\n'
|
2022-04-30 17:51:56 +00:00
|
|
|
try:
|
|
|
|
sock.sendall(json_str.encode('utf-8'))
|
|
|
|
except socket.error as exp:
|
|
|
|
sock = None
|
2022-04-28 21:16:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
operations = [OBJECT_PT_osci_render_settings, osci_render_connect, osci_render_close]
|
|
|
|
|
|
|
|
|
|
|
|
def register():
|
|
|
|
bpy.app.handlers.frame_change_pre.append(send_scene_to_osci_render)
|
|
|
|
bpy.app.handlers.depsgraph_update_post.append(send_scene_to_osci_render)
|
2022-04-30 17:51:56 +00:00
|
|
|
atexit.register(close_osci_render)
|
2022-04-28 21:16:12 +00:00
|
|
|
for operation in operations:
|
|
|
|
bpy.utils.register_class(operation)
|
|
|
|
|
|
|
|
|
|
|
|
def unregister():
|
2022-04-30 09:18:32 +00:00
|
|
|
bpy.app.handlers.frame_change_pre.remove(send_scene_to_osci_render)
|
|
|
|
bpy.app.handlers.depsgraph_update_post.remove(send_scene_to_osci_render)
|
2022-04-30 17:51:56 +00:00
|
|
|
atexit.unregister(close_osci_render)
|
2022-04-30 09:18:32 +00:00
|
|
|
for operation in reversed(operations):
|
2022-04-28 21:16:12 +00:00
|
|
|
bpy.utils.unregister_class(operation)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
register()
|