Commit d33b7692 authored by Bruno Laurencich's avatar Bruno Laurencich

customize transmition method

parent 6aaeac4f
......@@ -34,8 +34,9 @@ C = bpy.context
def check_local_ip(self, context):
chord_global = context.user_preferences.addons[__package__].preferences
if chord_global.trans_method != "Multicast":
chord_global.local_ip_addr = u.get_local_ip()
if chord_global.trans_method != "multi":
chord_global.ip_addr = u.get_local_ip()
class Chord_Properties(bpy.types.AddonPreferences):
"""A collection to hold all the global chordata properties.
......@@ -51,7 +52,7 @@ class Chord_Properties(bpy.types.AddonPreferences):
trans_method = props.EnumProperty(\
items= u.transmition_methods(),
default="Unicast",
default="uni",
update=check_local_ip)
net_submask = props.StringProperty( default = "255.255.255.0" )
......@@ -60,7 +61,7 @@ class Chord_Properties(bpy.types.AddonPreferences):
multicast_grp_addr = props.StringProperty( default = "239.0.0.1" )
local_ip_addr = props.StringProperty( default = u.get_local_ip() )
ip_addr = props.StringProperty( default = u.get_local_ip() )
notochord_dest_port = props.IntProperty( default = 6565 )
......@@ -71,6 +72,13 @@ class Chord_Properties(bpy.types.AddonPreferences):
show_advanced = props.BoolProperty( name="Show advanced panel", default = False )
show_send = props.BoolProperty( name="Show retransmision panel", default = False )
show_rec = props.BoolProperty( name="Show recording panel", default = False )
# ----------- RECORD -----------
do_set_keyframes = props.BoolProperty( name="Record capture", default = False )
playing = props.BoolProperty( name="Record capture", default = False )
# ----------- ADVANCED -----------
debug_osc = props.BoolProperty( name="Debug osc to console", default = False )
......@@ -86,12 +94,13 @@ class Chord_Properties(bpy.types.AddonPreferences):
# ----------- SEND -----------
class Send_Properties(bpy.types.PropertyGroup):
trans_method = props.EnumProperty(\
items= u.transmition_methods(),
default="Unicast")
items= u.transmition_methods() + [("none", "None", "None")] ,
default="none")
ip_addr = props.StringProperty( default = "127.0.0.1" )
multicast_grp_addr = props.StringProperty( default = "239.0.0.2" )
dest_port = props.IntProperty( default = 7000 )
net_submask = props.StringProperty( default = "255.255.255.0" )
send_rot = props.BoolProperty( name="Send rotation", default = True )
send_pos = props.BoolProperty( name="Send position", default = False )
......
......@@ -70,7 +70,6 @@ class Armature_Handler:
def reset_pose(self):
for b in self.object.pose.bones:
print("RESET" , b.name)
b.rotation_quaternion.identity()
......
......@@ -148,11 +148,11 @@ class Chord_Local_Ip(bpy.types.Operator):
@classmethod
def poll(cls, context):
chord_global = context.user_preferences.addons[__package__].preferences
return chord_global.trans_method is not "Multicast"
return chord_global.trans_method is not "multi"
def execute(self, context):
chord_global = context.user_preferences.addons[__package__].preferences
chord_global.local_ip_addr = u.get_local_ip()
chord_global.ip_addr = u.get_local_ip()
return {"FINISHED"}
......
......@@ -87,23 +87,57 @@ class Chord_tools_panel(bpy.types.Panel):
col = split.column()
# col.operator("my.button", text="21").loc="5 21"
if self.chord_global.trans_method == "Multicast":
col.label("Multicast group")
if self.chord_global.trans_method == "multi":
col.label("multi_id group")
col.prop(self.chord_global, "multicast_grp_addr", text="")
else:
col.label("Local address")
col.prop(self.chord_global, "local_ip_addr", text="")
col.prop(self.chord_global, "ip_addr", text="")
split = row.split()#percentage=0.25
col = split.column()
col.label("Port")
col.prop(self.chord_global, "notochord_dest_port", text="")
if self.chord_global.trans_method == "Broadcast":
if self.chord_global.trans_method == "broad":
row = box.row()
row.prop(self.chord_global, "net_submask", text="Net submask")
layout.prop(self.chord_global, "show_advanced")
layout.prop(self.chord_global, "show_send")
layout.prop(self.chord_global, "show_rec", icon="REC")
layout.prop(self.chord_global, "show_send", icon="MAN_TRANS")
layout.prop(self.chord_global, "show_advanced", icon="SETTINGS")
class Chord_rec_panel(bpy.types.Panel):
"""Recording options panel for the chordata client addon"""
bl_label = "Chordata Record/Play"
bl_category = "Chordata"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
@classmethod
def poll(cls, context):
chord_global = context.user_preferences.addons[__package__].preferences
return chord_global.show_rec
def draw(self, context):
self.chord_global = context.user_preferences.addons[__package__].preferences
layout = self.layout
if context.scene.chordata.target == None:
layout.active = False
row = layout.row()
row.scale_y = 2
row.prop(self.chord_global, "do_set_keyframes", icon="REC")
layout.operator("chordata.clean_anims", "Clean Animation", icon="GHOST")
row = layout.row(align=True)
row.alignment = 'EXPAND'
if not self.chord_global.playing:
row.operator("chordata.play", "Play and trasmit Animation", icon="PLAY")
else:
row.operator("chordata.play", "Playing..", icon="PLAY")
row.operator("chordata.stop", "Stop", icon="CANCEL")
class Chord_send_panel(bpy.types.Panel):
......@@ -121,6 +155,8 @@ class Chord_send_panel(bpy.types.Panel):
def draw(self, context):
self.chord_global = context.user_preferences.addons[__package__].preferences
layout = self.layout
if context.scene.chordata.target == None:
layout.active = False
box = layout.box()
box.label("Retransmision method", icon="MAN_TRANS")
row = box.row()
......@@ -131,8 +167,10 @@ class Chord_send_panel(bpy.types.Panel):
col = split.column()
# col.operator("my.button", text="21").loc="5 21"
if self.chord_global.send.trans_method == "Multicast":
col.label("Multicast group")
if self.chord_global.send.trans_method == "none":
return
elif self.chord_global.send.trans_method == "multi":
col.label("multi_id group")
col.prop(self.chord_global.send, "multicast_grp_addr", text="")
else:
col.label("Destination address")
......@@ -142,7 +180,7 @@ class Chord_send_panel(bpy.types.Panel):
col.label("Port")
col.prop(self.chord_global.send, "dest_port", text="")
if self.chord_global.send.trans_method == "Broadcast":
if self.chord_global.send.trans_method == "broad":
row = box.row()
row.prop(self.chord_global, "net_submask", text="Net submask")
......
......@@ -32,17 +32,52 @@ class Chord_Stop_Receive_OSC(bpy.types.Operator):
bl_label = "Chordata: Cancel Pose Data reception"
bl_options = {'REGISTER'}
@classmethod
def poll(cls, context):
return context.scene.chordata.target != None
def execute(self, context):
context.user_preferences.addons[__package__].preferences.receiving = False
return {"FINISHED"}
class Chord_Clean_Anims(bpy.types.Operator):
"""Unlink actions of the armature, and leave them with fake users"""
bl_idname = "chordata.clean_anims"
bl_label = "Chordata: Clean previous animations"
bl_options = {'REGISTER'}
@classmethod
def poll(cls, context):
return context.scene.chordata.target != None
def clean_prev_animations(self):
self.context.scene.frame_current = 0
try:
self.armature.animation_data.action.use_fake_user = True
self.armature.animation_data_clear()
except AttributeError:
u.write_blender_console(self.context, "No previous animation data found.")
def execute(self, context):
self.context = context
self.armature = context.scene.chordata.target
self.clean_prev_animations()
return {"FINISHED"}
class Chord_Receive_OSC(bpy.types.Operator):
"""Tries to get the ip of the notochord"""
"""Receives the capture and putsit on an armature"""
bl_idname = "chordata.receive"
bl_label = "Chordata: Receive pose Data"
bl_options = {'REGISTER'}
@classmethod
def poll(cls, context):
return context.scene.chordata.target != None \
and context.scene.chordata.target.type == "ARMATURE"
# ----------- UTILS -----------
def text(self, text = None):
if text:
......@@ -53,37 +88,28 @@ class Chord_Receive_OSC(bpy.types.Operator):
for a in self.views_3d:
a.header_text_set()
def clean_prev_animations(self):
self.context.scene.frame_current = 0
try:
self.armature.object.animation_data.action.use_fake_user = True
self.armature.object.animation_data_clear()
except AttributeError:
u.write_blender_console(self.context, "No previous animation data found.")
def prepare_armature(self):
self.clean_prev_animations()
bpy.ops.chordata.clean_anims()
self.armature.reset_pose()
self.do_set_keyframes = False
self.chord_global.do_set_keyframes = False
self.context.scene.frame_current = 0
self.context.scene.frame_start = 0
self.text(self.armature.message)
def start_stop_animation(self):
if self.do_set_keyframes:
self.do_set_keyframes = False
if self.chord_global.do_set_keyframes:
self.chord_global.do_set_keyframes = False
self.report({"INFO"}, "Stop recording animation")
else:
self.clean_prev_animations()
self.do_set_keyframes = True
bpy.ops.chordata.clean_anims()
self.chord_global.do_set_keyframes = True
self.report({"INFO"}, "Recording animation!")
def set_keyframe(self):
if self.do_set_keyframes:
if self.chord_global.do_set_keyframes:
self.armature.set_key(self.context)
self.context.scene.frame_current += 1
......@@ -150,7 +176,8 @@ class Chord_Receive_OSC(bpy.types.Operator):
if not self.start_server(): return {"CANCELLED"}
send.init_osc("Unicast", "127.0.0.1", 7000)
self.chord_global.send.net_submask = self.chord_global.net_submask
send.init_osc(self.chord_global.send)
return {'RUNNING_MODAL'}
......@@ -158,11 +185,9 @@ class Chord_Receive_OSC(bpy.types.Operator):
def start_server(self):
osc_startup()
server = u.transmition_methods(False)[self.chord_global.trans_method][2]
addr = "0.0.0.0"
if self.chord_global.trans_method == "Multicast":
addr = self.chord_global.local_ip_addr
method = self.chord_global.trans_method
server = u.transmition_methods(False)[method][2]
addr = u.get_transmition_addr(self.chord_global)
port= self.chord_global.notochord_dest_port
......@@ -172,17 +197,16 @@ class Chord_Receive_OSC(bpy.types.Operator):
u.write_blender_console(self.context, str(e))
self.report({"ERROR"}, "There was a problem creating the UDP server")
return False
### This was included directly in the library code:
# udpsock = osch.get_channel("chordata_armature_server").udpsock
# mreq = struct_pack("4sl",
# socket.inet_aton("239.0.0.1"),
# socket.INADDR_ANY)
# udpsock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
###
msg = "Receiving in %s:%d (%s)" % \
(addr, port, u.transmition_methods(False)[method][0])
print(msg)
try:
u.write_blender_console(bpy.context, msg)
except Exception as e:
print("Couldn't write to internal console..")
#TODO: work on the OSC routing, the library is not using regex but glob??
bone_handler = self.receive_bones
if self.chord_global.debug_osc: bone_handler = self.receive_bones_verbose
osc_method("/Chordata/*", bone_handler,\
......@@ -218,6 +242,7 @@ class Chord_Receive_OSC(bpy.types.Operator):
osch.get_channel("chordata_armature_server").terminate()
send.clean()
self.chord_global.receiving = False
self.chord_global.do_set_keyframes = False
self.text(None)
osc_terminate()
......@@ -60,16 +60,17 @@ class Chord_Start_Notochord(Chord_Runner_Base):
self.layout.label("Press OK to start the notochord, might take some seconds")
def check_local_ip(self):
if self.chord_global.local_ip_addr:
if self.chord_global.ip_addr:
return True
bpy.ops.chordata.get_local_ip()
if self.chord_global.local_ip_addr:
if self.chord_global.ip_addr:
return True
return False
def invoke(self, context, event):
self.chord_global = context.user_preferences.addons[__package__].preferences
if not self.check_local_ip():
......@@ -83,11 +84,7 @@ class Chord_Start_Notochord(Chord_Runner_Base):
for p in self.chord_global.notochord_parameters.split():
params += "p=%s&" % p
addr = self.chord_global.local_ip_addr
if self.chord_global.trans_method == "Broadcast":
addr = self.chord_global.local_ip_addr
subm = self.chord_global.net_submask
addr = u.get_broadcast_addr(addr, subm)
addr = u.get_transmition_addr(self.chord_global)
params += "p=%s&p=%s" % (addr, self.chord_global.notochord_dest_port)
......
......@@ -31,22 +31,108 @@ if "u" in locals():
else:
from . import utils as u
class Chord_Play_Animation(bpy.types.Operator):
"""Plays and transmits the recorded animation"""
bl_idname = "chordata.play"
bl_label = "Chordata: Play and transmit capture"
bl_options = {'REGISTER'}
@classmethod
def poll(cls, context):
chord_global = context.user_preferences.addons[__package__].preferences
return context.scene.chordata.target != None \
and chord_global.receiving == False \
and context.scene.chordata.target.animation_data \
and context.scene.chordata.target.animation_data.action
# ----------- EXECUTE -----------
def execute(self, context):
self.armature = context.scene.chordata.target
self.chord_global = context.user_preferences.addons[__package__].preferences
self.chord_global.playing = True
wm = context.window_manager
self._timer = wm.event_timer_add( \
1 / context.scene.render.fps,\
context.window)
wm.modal_handler_add(self)
curr = context.scene.frame_current
self.begin, self.end = self.armature.animation_data.action.frame_range
if curr < self.begin or curr > self.end:
context.scene.frame_current = self.begin
self.chord_global.send.net_submask = self.chord_global.net_submask
init_osc(self.chord_global.send)
self.report({"INFO"}, "Capture playing..")
return {'RUNNING_MODAL'}
# ----------- MODAL -----------
def modal(self, context, event):
if event.type == 'TIMER':
send_Armature(self.armature, self.chord_global.send)
osc_process()
context.scene.frame_current += 1
if context.scene.frame_current > self.end:
context.scene.frame_current = self.begin
elif event.type in {'RIGHTMOUSE', 'ESC'} or not self.chord_global.playing:
self.report({"WARNING"}, "Capture reproduction stopped")
self.cancel(context)
return {'CANCELLED'}
return {'PASS_THROUGH'}
# ----------- CANCEL -----------
def cancel(self, context):
wm = context.window_manager
wm.event_timer_remove(self._timer)
clean()
self.chord_global.playing = False
osc_terminate()
class Chord_Play_Animation(bpy.types.Operator):
"""Stops the reproduction of the animation"""
bl_idname = "chordata.stop"
bl_label = "Chordata: Stops capture reproduction and transmition"
bl_options = {'REGISTER'}
def execute(self, context):
self.chord_global = context.user_preferences.addons[__package__].preferences
self.chord_global.playing = False
return {"FINISHED"}
def init_osc(options):
method = options.trans_method
addr = u.get_transmition_addr(options)
port = options.dest_port
def init_osc(type, addr, port):
# Start the system.
print("Starting CLIENT!")
try:
osc_startup()
except:
print("OSC already initialized")
client = u.transmition_methods(False)[type][3]
client = u.transmition_methods(False)[method][3]
# Make client channels to send packets.
client(addr, port, "chordata_client")
msg = "Transmiting to %s:%d (%s)" % \
(addr, port, u.transmition_methods(False)[method][0])
print(msg)
try:
u.write_blender_console(bpy.context, msg)
except Exception as e:
print("Couldn't write to internal console..")
def send_Armature(arm, options):
msgs = []
......@@ -64,97 +150,9 @@ def send_Armature(arm, options):
bun = oscbuildparse.OSCBundle(oscbuildparse.OSC_IMMEDIATELY, msgs)
osc_send(bun, "chordata_client")
# osc_process()
# print("send")
def clean():
osch.get_channel("chordata_client").terminate()
# def send_init_msg(arm):
# client.send_message("/init", len(arm.pose.bones))
# def send_animation(arm):
# timeline = C.scene.frame_start, C.scene.frame_end
# send_init_msg(arm)
# delay = 1/C.scene.render.fps
# for i in range(*timeline):
# C.scene.frame_set(i)
# send_Armature(arm)
# sleep(delay)
# class send_anim_osc(bpy.types.Operator):
# """Receive quaternions from OSC and move an armature"""
# bl_idname = "armature.send_anim_osc"
# bl_label = "Send the animation trought OSC"
# @classmethod
# def poll(cls, context):
# return True
# def invoke(self, context, ev):
# # print("SEND INVOKE")
# return self.execute(context)
# def execute(self, context):
# deb = note_debouncer()
# piano_collide.unregister()
# send_animation(context.object)
# return {"FINISHED"}
# class send_osc(bpy.types.Operator):
# """Receive quaternions from OSC and move an armature"""
# bl_idname = "armature.send_still_osc"
# bl_label = "Send the pose trought OSC"
# @classmethod
# def poll(cls, context):
# return True
# def invoke(self, context, ev):
# # print("SEND INVOKE")
# return self.execute(context)
# def execute(self, context):
# # deb = note_debouncer()
# # piano_collide.unregister()
# send_Armature(context.object)
# return {"FINISHED"}
# def register():
# print("SENDING OSC to {}:{}".format(IP, PORT))
# bpy.utils.register_class(send_osc)
# bpy.utils.register_class(send_anim_osc)
# def unregister():
# bpy.utils.unregister_class(send_osc)
# bpy.utils.unregister_class(send_anim_osc)
# if __name__ == '__main__':
# register()
# # send_animation(D.objects["TARGET"])
......@@ -7,6 +7,17 @@ from osc4py3.as_comthreads import *
import ipaddress
import socket
def get_transmition_addr(options):
# import pdb; pdb.set_trace()
addr = options.ip_addr
if options.trans_method == "broad":
addr = options.ip_addr
subm = options.net_submask
addr = get_broadcast_addr(addr, subm)
elif options.trans_method == "multi":
addr = options.multicast_grp_addr
return addr
def get_local_ip():
"""Get local ip, from https://stackoverflow.com/a/28950776 """
......@@ -32,13 +43,13 @@ def transmition_methods(as_tuples = True):
"""Transmision method to be used"""
o = osc4py3.as_comthreads
d = {
"Unicast": ("uni", 0, o.osc_udp_server, o.osc_udp_client),
"Multicast": ("multi", 1, o.osc_multicast_server, o.osc_multicast_client),
"Broadcast": ("broad", 2, o.osc_broadcast_server, o.osc_broadcast_client),
"uni": ("Unicast", 0, o.osc_udp_server, o.osc_udp_client),
"multi": ("Multicast", 1, o.osc_multicast_server, o.osc_multicast_client),
"broad": ("Broadcast", 2, o.osc_broadcast_server, o.osc_broadcast_client),
}
if as_tuples:
return [(name, v[0], name, "", v[1] ) for name, v in d.items()]
return [(name, v[0], v[0] + " transmition", "", v[1] ) for name, v in d.items()]
return d
......@@ -58,7 +69,7 @@ def sending_props(as_tuples = True):
def get_broadcast_addr(addr, submask):
return ipaddress.IPv4Network( "%s/%s" % (addr, submask), False).broadcast_address
return str(ipaddress.IPv4Network( "%s/%s" % (addr, submask), False).broadcast_address)
def possible_states():
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment