def send_object_visibility(client: Client, object_: bpy.types.Object): logger.debug("send_object_visibility %s", object_.name_full) buffer = (common.encode_string(object_.name_full) + common.encode_bool(object_.hide_viewport) + common.encode_bool(object_.hide_select) + common.encode_bool(object_.hide_render) + common.encode_bool(object_.hide_get())) client.add_command( common.Command(common.MessageType.OBJECT_VISIBILITY, buffer, 0))
def send_collection(client: Client, collection: bpy.types.Collection): logger.info("send_collection %s", collection.name_full) collection_instance_offset = collection.instance_offset temporary_visibility = True layer_collection = share_data.blender_layer_collections.get( collection.name_full) if layer_collection: temporary_visibility = not layer_collection.hide_viewport buffer = (common.encode_string(collection.name_full) + common.encode_bool(not collection.hide_viewport) + common.encode_vector3(collection_instance_offset) + common.encode_bool(temporary_visibility)) client.add_command(common.Command(common.MessageType.COLLECTION, buffer, 0))
def send_grease_pencil_layer(layer, name): buffer = common.encode_string(name) buffer += common.encode_bool(layer.hide) buffer += common.encode_int(len(layer.frames)) for frame in layer.frames: buffer += send_grease_pencil_frame(frame) return buffer
def grab(self, host, port, room_name: str): with Client(host, port) as client: client.join_room(room_name) attempts_max = 20 attempts = 0 try: while attempts < attempts_max: received_commands = client.fetch_incoming_commands() attempts += 1 time.sleep(0.01) for command in received_commands: attempts = 0 if command.type <= MessageType.COMMAND: continue # Ignore command serial Id, that may not match command.id = 0 self.streams.data[command.type].append(command.data) except ClientDisconnectedException: print("Grabber: disconnected before received command stream.", file=sys.stderr) client.send_command( Command(MessageType.SET_ROOM_KEEP_OPEN, encode_string(room_name) + encode_bool(False))) client.send_command( Command(MessageType.LEAVE_ROOM, room_name.encode("utf8"))) if not client.wait(MessageType.LEAVE_ROOM): print("Grabber: disconnected before receiving LEAVE_ROOM.", file=sys.stderr)
def get_camera_buffer(obj): cam = obj.data focal = cam.lens front_clip_plane = cam.clip_start far_clip_plane = cam.clip_end dof_enabled = cam.dof.use_dof aperture = cam.dof.aperture_fstop colimator_name = cam.dof.focus_object.name_full if cam.dof.focus_object is not None else "" sensor_fit_name = cam.sensor_fit sensor_fit = common.SensorFitMode.AUTO if sensor_fit_name == "AUTO": sensor_fit = common.SensorFitMode.AUTO elif sensor_fit_name == "HORIZONTAL": sensor_fit = common.SensorFitMode.HORIZONTAL elif sensor_fit_name == "VERTICAL": sensor_fit = common.SensorFitMode.VERTICAL sensor_width = cam.sensor_width sensor_height = cam.sensor_height path = get_object_path(obj) return (common.encode_string(path) + common.encode_string(obj.name_full) + common.encode_float(focal) + common.encode_float(front_clip_plane) + common.encode_float(far_clip_plane) + common.encode_bool(dof_enabled) + common.encode_float(aperture) + common.encode_string(colimator_name) + common.encode_int(sensor_fit.value) + common.encode_float(sensor_width) + common.encode_float(sensor_height))
def join_room( self, room_name: str, blender_version: str, mixer_version: str, ignore_version_check: bool, generic_protocol: bool, ): name = common.encode_string(room_name) bl_version = common.encode_string(blender_version) mix_version = common.encode_string(mixer_version) version_check = common.encode_bool(ignore_version_check) protocol = common.encode_bool(generic_protocol) return self.send_command( common.Command( common.MessageType.JOIN_ROOM, name + bl_version + mix_version + version_check + protocol, 0))
def send_scene(): get_state() buffer = common.encode_int(len(share_data.shot_manager.shots)) for s in share_data.shot_manager.shots: buffer += (common.encode_string(s.name) + common.encode_string(s.camera_name) + common.encode_int(s.start) + common.encode_int(s.end) + common.encode_bool(s.enabled)) share_data.client.add_command( common.Command(common.MessageType.SHOT_MANAGER_CONTENT, buffer, 0))
def send_grease_pencil_material(client: Client, material): gp_material = material.grease_pencil stroke_enable = gp_material.show_stroke stroke_mode = gp_material.mode stroke_style = gp_material.stroke_style stroke_color = gp_material.color stroke_overlap = gp_material.use_overlap_strokes fill_enable = gp_material.show_fill fill_style = gp_material.fill_style fill_color = gp_material.fill_color gp_material_buffer = common.encode_string(material.name_full) gp_material_buffer += common.encode_bool(stroke_enable) gp_material_buffer += common.encode_string(stroke_mode) gp_material_buffer += common.encode_string(stroke_style) gp_material_buffer += common.encode_color(stroke_color) gp_material_buffer += common.encode_bool(stroke_overlap) gp_material_buffer += common.encode_bool(fill_enable) gp_material_buffer += common.encode_string(fill_style) gp_material_buffer += common.encode_color(fill_color) client.add_command(common.Command(common.MessageType.GREASE_PENCIL_MATERIAL, gp_material_buffer, 0))
def grab(self, host, port, room_name: str): with Client(host, port) as client: client.join_room(room_name, "ignored", "ignored", True, True) attempts_max = 20 attempts = 0 try: while attempts < attempts_max: received_commands = client.fetch_incoming_commands() attempts += 1 time.sleep(0.01) for command in received_commands: attempts = 0 if command.type == MessageType.SEND_ERROR: message = decode_string(command.data, 0) raise RuntimeError( f"Received error message {message}") if command.type <= MessageType.COMMAND: continue # Ignore command serial Id, that may not match command.id = 0 self.streams.commands[command.type].append(command) except ClientDisconnectedException: raise RuntimeError( "Grabber: disconnected before received command stream.") client.send_command( Command(MessageType.SET_ROOM_KEEP_OPEN, encode_string(room_name) + encode_bool(False))) client.send_command( Command(MessageType.LEAVE_ROOM, room_name.encode("utf8"))) if not client.wait(MessageType.LEAVE_ROOM): raise RuntimeError( "Grabber: disconnected before receiving LEAVE_ROOM.") count = sum( [len(commands) for commands in self.streams.commands.values()]) assert count > 0, "No message grabbed"
def send_grease_pencil_time_offset(client: Client, obj): grease_pencil = obj.data buffer = common.encode_string(grease_pencil.name_full) for modifier in obj.grease_pencil_modifiers: if modifier.type != "GP_TIME": continue offset = modifier.offset scale = modifier.frame_scale custom_range = modifier.use_custom_frame_range frame_start = modifier.frame_start frame_end = modifier.frame_end buffer += (common.encode_int(offset) + common.encode_float(scale) + common.encode_bool(custom_range) + common.encode_int(frame_start) + common.encode_int(frame_end)) client.add_command( common.Command(common.MessageType.GREASE_PENCIL_TIME_OFFSET, buffer, 0)) break
def set_room_keep_open(self, room_name: str, value: bool): return self.send_command( common.Command( common.MessageType.SET_ROOM_KEEP_OPEN, common.encode_string(room_name) + common.encode_bool(value), 0 ) )
def send_montage_mode(): buffer = common.encode_bool(share_data.shot_manager.montage_mode) share_data.client.add_command( common.Command(common.MessageType.SHOT_MANAGER_MONTAGE_MODE, buffer, 0))
def encode_base_mesh(obj): # Temporary for curves and other objects that support to_mesh() # #todo Implement correct base encoding for these objects mesh_data = obj.data if obj.type == "MESH" else obj.to_mesh() if mesh_data is None: # This happens for empty curves # This is temporary, when curves will be fully implemented we will encode something return bytes() binary_buffer = encode_base_mesh_geometry(mesh_data) # Shape keys # source https://blender.stackexchange.com/questions/111661/creating-shape-keys-using-python if mesh_data.shape_keys is None: binary_buffer += common.encode_int(0) # Indicate 0 key blocks else: logger.debug("Writing %d shape keys", len(mesh_data.shape_keys.key_blocks)) binary_buffer += common.encode_int(len( mesh_data.shape_keys.key_blocks)) # Encode names for key_block in mesh_data.shape_keys.key_blocks: binary_buffer += common.encode_string(key_block.name) # Encode vertex group names for key_block in mesh_data.shape_keys.key_blocks: binary_buffer += common.encode_string(key_block.vertex_group) # Encode relative key names for key_block in mesh_data.shape_keys.key_blocks: binary_buffer += common.encode_string(key_block.relative_key.name) # Encode data shape_keys_buffer = [] fmt_str = "" for key_block in mesh_data.shape_keys.key_blocks: shape_keys_buffer.extend( (key_block.mute, key_block.value, key_block.slider_min, key_block.slider_max, len(key_block.data))) fmt_str += f"1I1f1f1f1I{(3 * len(key_block.data))}f" for i in range(len(key_block.data)): shape_keys_buffer.extend(key_block.data[i].co) binary_buffer += struct.pack(f"{fmt_str}", *shape_keys_buffer) binary_buffer += common.encode_bool(mesh_data.shape_keys.use_relative) # Vertex Groups verts_per_group = {} for vertex_group in obj.vertex_groups: verts_per_group[vertex_group.index] = [] for vert in mesh_data.vertices: for vg in vert.groups: verts_per_group[vg.group].append((vert.index, vg.weight)) binary_buffer += common.encode_int(len(obj.vertex_groups)) for vertex_group in obj.vertex_groups: binary_buffer += common.encode_string(vertex_group.name) binary_buffer += common.encode_bool(vertex_group.lock_weight) binary_buffer += common.encode_int( len(verts_per_group[vertex_group.index])) for vg_elmt in verts_per_group[vertex_group.index]: binary_buffer += common.encode_int(vg_elmt[0]) binary_buffer += common.encode_float(vg_elmt[1]) # Normals binary_buffer += common.encode_bool(mesh_data.use_auto_smooth) binary_buffer += common.encode_float(mesh_data.auto_smooth_angle) binary_buffer += common.encode_bool(mesh_data.has_custom_normals) if mesh_data.has_custom_normals: mesh_data.calc_normals_split( ) # Required otherwise all normals are (0, 0, 0) normals = [] for loop in mesh_data.loops: normals.extend((*loop.normal, )) binary_buffer += struct.pack(f"{len(normals)}f", *normals) # UV Maps for uv_layer in mesh_data.uv_layers: binary_buffer += common.encode_string(uv_layer.name) binary_buffer += common.encode_bool(uv_layer.active_render) # Vertex Colors for vertex_colors in mesh_data.vertex_colors: binary_buffer += common.encode_string(vertex_colors.name) binary_buffer += common.encode_bool(vertex_colors.active_render) if obj.type != "MESH": obj.to_mesh_clear() return binary_buffer