def send_animation_buffer(self, obj_name, animation_data, channel_name, channel_index=-1): if not animation_data: return action = animation_data.action if not action: buffer = ( common.encode_string(obj_name) + common.encode_string(channel_name) + common.encode_int(channel_index) + common.int_to_bytes(0, 4) # send empty buffer ) self.add_command(common.Command(MessageType.ANIMATION, buffer, 0)) return for fcurve in action.fcurves: if fcurve.data_path == channel_name: if channel_index == -1 or fcurve.array_index == channel_index: key_count = len(fcurve.keyframe_points) times = [] values = [] for keyframe in fcurve.keyframe_points: times.append(int(keyframe.co[0])) values.append(keyframe.co[1]) buffer = ( common.encode_string(obj_name) + common.encode_string(channel_name) + common.encode_int(channel_index) + common.int_to_bytes(key_count, 4) + struct.pack(f"{len(times)}i", *times) + struct.pack(f"{len(values)}f", *values) ) self.add_command(common.Command(MessageType.ANIMATION, buffer, 0)) return
def get_rename_buffer(self, old_name, new_name): encoded_old_name = old_name.encode() encoded_new_name = new_name.encode() buffer = (common.int_to_bytes(len(encoded_old_name), 4) + encoded_old_name + common.int_to_bytes(len(encoded_new_name), 4) + encoded_new_name) return buffer
def send_grease_pencil_stroke(stroke): buffer = common.encode_int(stroke.material_index) buffer += common.encode_int(stroke.line_width) points = list() for point in stroke.points: points.extend(point.co) points.append(point.pressure) points.append(point.strength) binary_points_buffer = common.int_to_bytes(len(stroke.points), 4) + struct.pack(f"{len(points)}f", *points) buffer += binary_points_buffer return buffer
def get_delete_buffer(self, name): encoded_name = name.encode() buffer = common.int_to_bytes(len(encoded_name), 4) + encoded_name return buffer
def encode_baked_mesh(obj): """ Bake an object as a triangle mesh and encode it. """ stats_timer = share_data.current_stats_timer # Bake modifiers depsgraph = bpy.context.evaluated_depsgraph_get() obj = obj.evaluated_get(depsgraph) stats_timer.checkpoint("eval_depsgraph") # Triangulate mesh (before calculating normals) mesh = obj.data if obj.type == "MESH" else obj.to_mesh() if mesh is None: # This happens for empty curves return bytes() bm = bmesh.new() bm.from_mesh(mesh) bmesh.ops.triangulate(bm, faces=bm.faces) bm.to_mesh(mesh) bm.free() stats_timer.checkpoint("triangulate_mesh") # Calculate normals, necessary if auto-smooth option enabled mesh.calc_normals() mesh.calc_normals_split() # calc_loop_triangles resets normals so... don't use it stats_timer.checkpoint("calc_normals") # get active uv layer uvlayer = mesh.uv_layers.active vertices = [] normals = [] uvs = [] indices = [] material_indices = [] # array of triangle index, material index current_material_index = -1 current_face_index = 0 logger.debug("Writing %d polygons", len(mesh.polygons)) for f in mesh.polygons: for loop_id in f.loop_indices: index = mesh.loops[loop_id].vertex_index vertices.extend(mesh.vertices[index].co) normals.extend(mesh.loops[loop_id].normal) if uvlayer: uvs.extend([x for x in uvlayer.data[loop_id].uv]) indices.append(loop_id) if f.material_index != current_material_index: current_material_index = f.material_index material_indices.append(current_face_index) material_indices.append(current_material_index) current_face_index = current_face_index + 1 if obj.type != "MESH": obj.to_mesh_clear() stats_timer.checkpoint("make_buffers") # Vericex count + binary vertices buffer size = len(vertices) // 3 binary_vertices_buffer = common.int_to_bytes(size, 4) + struct.pack( f"{len(vertices)}f", *vertices) stats_timer.checkpoint("write_verts") # Normals count + binary normals buffer size = len(normals) // 3 binary_normals_buffer = common.int_to_bytes(size, 4) + struct.pack( f"{len(normals)}f", *normals) stats_timer.checkpoint("write_normals") # UVs count + binary uvs buffer size = len(uvs) // 2 binary_uvs_buffer = common.int_to_bytes(size, 4) + struct.pack( f"{len(uvs)}f", *uvs) stats_timer.checkpoint("write_uvs") # material indices + binary material indices buffer size = len(material_indices) // 2 binary_material_indices_buffer = common.int_to_bytes( size, 4) + struct.pack(f"{len(material_indices)}I", *material_indices) stats_timer.checkpoint("write_material_indices") # triangle indices count + binary triangle indices buffer size = len(indices) // 3 binary_indices_buffer = common.int_to_bytes(size, 4) + struct.pack( f"{len(indices)}I", *indices) stats_timer.checkpoint("write_tri_idx_buff") return (binary_vertices_buffer + binary_normals_buffer + binary_uvs_buffer + binary_material_indices_buffer + binary_indices_buffer)
def encode_baked_mesh(obj): """ Bake an object as a triangle mesh and encode it. """ stats_timer = share_data.current_stats_timer # Bake modifiers depsgraph = bpy.context.evaluated_depsgraph_get() obj = obj.evaluated_get(depsgraph) stats_timer.checkpoint("eval_depsgraph") # Triangulate mesh (before calculating normals) mesh = obj.data if obj.type == "MESH" else obj.to_mesh() if mesh is None: # This happens for empty curves return bytes() original_bm = None if obj.type == "MESH": # Mesh is restored later only if is has not been generated from a curve or something else original_bm = bmesh.new() original_bm.from_mesh(mesh) bm = bmesh.new() bm.from_mesh(mesh) bmesh.ops.triangulate(bm, faces=bm.faces) bm.to_mesh(mesh) bm.free() stats_timer.checkpoint("triangulate_mesh") # Calculate normals, necessary if auto-smooth option enabled mesh.calc_normals() mesh.calc_normals_split() # calc_loop_triangles resets normals so... don't use it stats_timer.checkpoint("calc_normals") # get active uv layer uvlayer = mesh.uv_layers.active vertices = array.array("d", (0.0, )) * len(mesh.vertices) * 3 mesh.vertices.foreach_get("co", vertices) normals = array.array("d", (0.0, )) * len(mesh.loops) * 3 mesh.loops.foreach_get("normal", normals) if uvlayer: uvs = array.array("d", (0.0, )) * len(mesh.loops) * 2 mesh.uv_layers[0].data.foreach_get("uv", uvs) else: uvs = [] indices = array.array("i", (0, )) * len(mesh.loops) mesh.loops.foreach_get("vertex_index", indices) if len(obj.material_slots) <= 1: material_indices = [] else: material_indices = array.array("i", (0, )) * len(mesh.polygons) mesh.polygons.foreach_get("material_index", material_indices) if obj.type != "MESH": obj.to_mesh_clear() else: original_bm.to_mesh(mesh) original_bm.free() stats_timer.checkpoint("make_buffers") # Vericex count + binary vertices buffer size = len(vertices) // 3 binary_vertices_buffer = common.int_to_bytes(size, 4) + struct.pack( f"{len(vertices)}f", *vertices) stats_timer.checkpoint("write_verts") # Normals count + binary normals buffer size = len(normals) // 3 binary_normals_buffer = common.int_to_bytes(size, 4) + struct.pack( f"{len(normals)}f", *normals) stats_timer.checkpoint("write_normals") # UVs count + binary uvs buffer size = len(uvs) // 2 binary_uvs_buffer = common.int_to_bytes(size, 4) + struct.pack( f"{len(uvs)}f", *uvs) stats_timer.checkpoint("write_uvs") # material indices + binary material indices buffer size = len(material_indices) binary_material_indices_buffer = common.int_to_bytes( size, 4) + struct.pack(f"{len(material_indices)}I", *material_indices) stats_timer.checkpoint("write_material_indices") # triangle indices count + binary triangle indices buffer size = len(indices) // 3 binary_indices_buffer = common.int_to_bytes(size, 4) + struct.pack( f"{len(indices)}I", *indices) stats_timer.checkpoint("write_tri_idx_buff") return (binary_vertices_buffer + binary_normals_buffer + binary_uvs_buffer + binary_material_indices_buffer + binary_indices_buffer)