diff --git a/bl_types/bl_camera.py b/bl_types/bl_camera.py new file mode 100644 index 0000000..5a4cf8d --- /dev/null +++ b/bl_types/bl_camera.py @@ -0,0 +1,28 @@ +import bpy +import mathutils + +from .. import utils +from ..libs.replication.data import ReplicatedDatablock + +class BlCamera(ReplicatedDatablock): + def __init__(self, *args, **kwargs): + self.icon = 'CAMERA_DATA' + + super().__init__( *args, **kwargs) + + def load(self, data, target): + if target is None: + target = bpy.data.cameras.new(data["name"]) + + utils.dump_anything.load(target, data) + + + def dump(self, pointer=None): + assert(pointer) + + return utils.dump_datablock(pointer, 1) + +bl_id = "cameras" +bl_class = bpy.types.Camera +bl_rep_class = BlCamera + diff --git a/bl_types/bl_collection.py b/bl_types/bl_collection.py new file mode 100644 index 0000000..000266d --- /dev/null +++ b/bl_types/bl_collection.py @@ -0,0 +1,52 @@ +import bpy +import mathutils + +from .. import utils +from ..libs.replication.data import ReplicatedDatablock + + +class BlCollection(ReplicatedDatablock): + def __init__(self, *args, **kwargs): + self.icon = 'CAMERA_DATA' + + super().__init__(*args, **kwargs) + + def load(self, data, target): + + if target is None: + target = bpy.data.collections.new(data["name"]) + + # Load other meshes metadata + # dump_anything.load(target, data) + + # link objects + for object in data["objects"]: + if object not in target.objects.keys(): + target.objects.link(bpy.data.objects[object]) + + for object in target.objects.keys(): + if object not in data["objects"]: + target.objects.unlink(bpy.data.objects[object]) + + # Link childrens + for collection in data["children"]: + if collection not in target.children.keys(): + if bpy.data.collections.find(collection) == -1: + target.children.link( + bpy.data.collections[collection]) + + for collection in target.children.keys(): + if collection not in data["children"]: + target.collection.children.unlink( + bpy.data.collections[collection]) + + utils.dump_anything.load(target, data) + + def dump(self, pointer=None): + assert(pointer) + return utils.dump_datablock(pointer, 4) + + +bl_id = "collections" +bl_class = bpy.types.Collection +bl_rep_class = BlCollection diff --git a/bl_types/bl_curve.py b/bl_types/bl_curve.py new file mode 100644 index 0000000..f64fade --- /dev/null +++ b/bl_types/bl_curve.py @@ -0,0 +1,50 @@ +import bpy +import mathutils + +from .. import utils +from ..libs.replication.data import ReplicatedDatablock + +class BlCurve(ReplicatedDatablock): + def __init__(self, *args, **kwargs): + self.icon = 'CURVE_DATA' + + super().__init__( *args, **kwargs) + + def load(self, data, target): + if target is None: + target = bpy.data.curves.new(data["name"], 'CURVE') + + utils.dump_anything.load(target, data) + + target.splines.clear() + # load splines + for spline in data['splines']: + # Update existing.. + # if spline in target.splines.keys(): + + new_spline = target.splines.new(data['splines'][spline]['type']) + utils.dump_anything.load(new_spline, data['splines'][spline]) + + # Load curve geometry data + for bezier_point_index in data['splines'][spline]["bezier_points"]: + new_spline.bezier_points.add(1) + utils.dump_anything.load( + new_spline.bezier_points[bezier_point_index], data['splines'][spline]["bezier_points"][bezier_point_index]) + + for point_index in data['splines'][spline]["points"]: + new_spline.points.add(1) + utils.dump_anything.load( + new_spline.points[point_index], data['splines'][spline]["points"][point_index]) + + + def dump(self, pointer=None): + assert(pointer) + data = utils.dump_datablock(pointer, 1) + utils.dump_datablock_attibutes( + pointer, ['splines'], 5, data) + return data + +bl_id = "curves" +bl_class = bpy.types.Curve +bl_rep_class = BlCurve + diff --git a/bl_types/bl_gpencil.py b/bl_types/bl_gpencil.py new file mode 100644 index 0000000..62c194e --- /dev/null +++ b/bl_types/bl_gpencil.py @@ -0,0 +1,74 @@ +import bpy +import mathutils + +from .. import utils +from ..libs.replication.data import ReplicatedDatablock + +def load_gpencil_layer(target=None, data=None, create=False): + + utils.dump_anything.load(target, data) + + for frame in data["frames"]: + try: + tframe = target.frames[frame] + except: + tframe = target.frames.new(frame) + utils.dump_anything.load(tframe, data["frames"][frame]) + for stroke in data["frames"][frame]["strokes"]: + try: + tstroke = tframe.strokes[stroke] + except: + tstroke = tframe.strokes.new() + utils.dump_anything.load( + tstroke, data["frames"][frame]["strokes"][stroke]) + + for point in data["frames"][frame]["strokes"][stroke]["points"]: + p = data["frames"][frame]["strokes"][stroke]["points"][point] + + tstroke.points.add(1) + tpoint = tstroke.points[len(tstroke.points)-1] + + utils.dump_anything.load(tpoint, p) + +class BlGpencil(ReplicatedDatablock): + def __init__(self, *args, **kwargs): + self.icon = 'CAMERA_DATA' + + super().__init__( *args, **kwargs) + + def load(self, data, target): + if target is None: + target = bpy.data.grease_pencils.new(data["name"]) + + for layer in target.layers: + target.layers.remove(layer) + + if "layers" in data.keys(): + for layer in data["layers"]: + if layer not in target.layers.keys(): + gp_layer = target.layers.new(data["layers"][layer]["info"]) + else: + gp_layer = target.layers[layer] + load_gpencil_layer( + target=gp_layer, data=data["layers"][layer], create=create) + + utils.dump_anything.load(target, data) + + target.materials.clear() + if "materials" in data.keys(): + for mat in data['materials']: + target.materials.append(bpy.data.materials[mat]) + + + + def dump(self, pointer=None): + assert(pointer) + data = utils.dump_datablock(pointer, 2) + utils.dump_datablock_attibutes( + pointer, ['layers'], 9, data) + return data + +bl_id = "grease_pencils" +bl_class = bpy.types.GreasePencil +bl_rep_class = BlGpencil + diff --git a/bl_types/bl_image.py b/bl_types/bl_image.py new file mode 100644 index 0000000..44cf79a --- /dev/null +++ b/bl_types/bl_image.py @@ -0,0 +1,51 @@ +import bpy +import mathutils +import os + +from .. import utils, environment +from ..libs.replication.data import ReplicatedDatablock + +class BlImage(ReplicatedDatablock): + def __init__(self, *args, **kwargs): + self.icon = 'CAMERA_DATA' + + super().__init__( *args, **kwargs) + + def load(self, data, target): + if not target: + image = bpy.data.images.new( + name=data['name'], + width=data['size'][0], + height=data['size'][1] + ) + else: + image = target + + img_name = "{}.png".format(image.name) + + img_path = os.path.join(environment.CACHE_DIR, img_name) + + file = open(img_path, 'wb') + file.write(data["pixels"]) + file.close() + + image.source = 'FILE' + image.filepath = img_path + + + def dump(self, pointer=None): + assert(pointer) + data = {} + data['pixels'] = utils.dump_image(pointer) + utils.dump_datablock_attibutes(pointer, [], 2, data) + data = utils.dump_datablock_attibutes( + pointer, + ["name", 'size', 'height', 'alpha', 'float_buffer', 'filepath', 'source'], + 2, + data) + return data + +bl_id = "images" +bl_class = bpy.types.Image +bl_rep_class = BlImage + diff --git a/bl_types/bl_lights.py b/bl_types/bl_lights.py new file mode 100644 index 0000000..821885f --- /dev/null +++ b/bl_types/bl_lights.py @@ -0,0 +1,28 @@ +import bpy +import mathutils + +from .. import utils +from ..libs.replication.data import ReplicatedDatablock + +class BlLight(ReplicatedDatablock): + def __init__(self, *args, **kwargs): + self.icon = 'LIGHT_DATA' + + super().__init__( *args, **kwargs) + + def load(self, data, target): + if target is None: + target = bpy.data.lights.new(data["name"], data["type"]) + + utils.dump_anything.load(target, data) + + + def dump(self, pointer=None): + assert(pointer) + + return utils.dump_datablock(pointer, 3) + +bl_id = "lights" +bl_class = bpy.types.Light +bl_rep_class = BlLight + diff --git a/bl_types/bl_material.py b/bl_types/bl_material.py new file mode 100644 index 0000000..d154977 --- /dev/null +++ b/bl_types/bl_material.py @@ -0,0 +1,83 @@ +import bpy +import mathutils + +from .. import utils +from ..libs.replication.data import ReplicatedDatablock + +class BlMaterial(ReplicatedDatablock): + def __init__(self, *args, **kwargs): + self.icon = 'CAMERA_DATA' + + super().__init__( *args, **kwargs) + + def load(self, data, target): + if target is None: + target = bpy.data.materials.new(data["name"]) + + if data['is_grease_pencil']: + if not target.is_grease_pencil: + bpy.data.materials.create_gpencil_data(target) + + utils.dump_anything.load(target.grease_pencil, data['grease_pencil']) + + utils.load_dict(data['grease_pencil'], target.grease_pencil) + + elif data["use_nodes"]: + if target.node_tree is None: + target.use_nodes = True + + target.node_tree.nodes.clear() + + for node in data["node_tree"]["nodes"]: + # fix None node tree error + + index = target.node_tree.nodes.find(node) + + if index is -1: + node_type = data["node_tree"]["nodes"][node]["bl_idname"] + + target.node_tree.nodes.new(type=node_type) + + utils.dump_anything.load( + target.node_tree.nodes[index], data["node_tree"]["nodes"][node]) + + if data["node_tree"]["nodes"][node]['type'] == 'TEX_IMAGE': + target.node_tree.nodes[index].image = bpy.data.images[data["node_tree"] + ["nodes"][node]['image']['name']] + + for input in data["node_tree"]["nodes"][node]["inputs"]: + + try: + if hasattr(target.node_tree.nodes[index].inputs[input], "default_value"): + target.node_tree.nodes[index].inputs[input].default_value = data[ + "node_tree"]["nodes"][node]["inputs"][input]["default_value"] + except Exception as e: + continue + + # Load nodes links + target.node_tree.links.clear() + + for link in data["node_tree"]["links"]: + current_link = data["node_tree"]["links"][link] + input_socket = target.node_tree.nodes[current_link['to_node'] + ['name']].inputs[current_link['to_socket']['name']] + output_socket = target.node_tree.nodes[current_link['from_node'] + ['name']].outputs[current_link['from_socket']['name']] + + target.node_tree.links.new(input_socket, output_socket) + + + def dump(self, pointer=None): + assert(pointer) + data = utils.dump_datablock(pointer, 2) + if pointer.node_tree: + utils.dump_datablock_attibutes( + pointer.node_tree, ["nodes", "links"], 5, data['node_tree']) + elif pointer.grease_pencil: + utils.dump_datablock_attibutes(pointer, ["grease_pencil"], 3, data) + return data + +bl_id = "materials" +bl_class = bpy.types.Material +bl_rep_class = BlMaterial + diff --git a/bl_types/bl_mesh.py b/bl_types/bl_mesh.py index d262077..aca6ed5 100644 --- a/bl_types/bl_mesh.py +++ b/bl_types/bl_mesh.py @@ -5,6 +5,71 @@ import mathutils from .. import utils from ..libs.replication.data import ReplicatedDatablock +def dump_mesh(mesh, data={}): + import bmesh + + mesh_data = data + mesh_buffer = bmesh.new() + + mesh_buffer.from_mesh(mesh) + + uv_layer = mesh_buffer.loops.layers.uv.verify() + bevel_layer = mesh_buffer.verts.layers.bevel_weight.verify() + skin_layer = mesh_buffer.verts.layers.skin.verify() + + verts = {} + for vert in mesh_buffer.verts: + v = {} + v["co"] = list(vert.co) + + # vert metadata + v['bevel'] = vert[bevel_layer] + # v['skin'] = list(vert[skin_layer]) + + verts[str(vert.index)] = v + + mesh_data["verts"] = verts + + edges = {} + for edge in mesh_buffer.edges: + e = {} + e["verts"] = [edge.verts[0].index, edge.verts[1].index] + + # Edge metadata + e["smooth"] = edge.smooth + + edges[edge.index] = e + mesh_data["edges"] = edges + + faces = {} + for face in mesh_buffer.faces: + f = {} + fverts = [] + for vert in face.verts: + fverts.append(vert.index) + + f["verts"] = fverts + f["material_index"] = face.material_index + + uvs = [] + # Face metadata + for loop in face.loops: + loop_uv = loop[uv_layer] + + uvs.append(list(loop_uv.uv)) + + f["uv"] = uvs + faces[face.index] = f + + mesh_data["faces"] = faces + + uv_layers = [] + for uv_layer in mesh.uv_layers: + uv_layers.append(uv_layer.name) + + mesh_data["uv_layers"] = uv_layers + return mesh_data + class BlMesh(ReplicatedDatablock): def __init__(self, *args, **kwargs): self.icon = 'MESH_DATA' @@ -13,38 +78,63 @@ class BlMesh(ReplicatedDatablock): def load(self, data, target): if not target or not target.is_editmode: - # LOAD GEOMETRY + # 1 - LOAD GEOMETRY mesh_buffer = bmesh.new() - for i in data["vertices"]: - v = mesh_buffer.verts.new(data["vertices"][i]["co"]) - v.normal = data["vertices"][i]["normal"] + for i in data["verts"]: + v = mesh_buffer.verts.new(data["verts"][i]["co"]) mesh_buffer.verts.ensure_lookup_table() for i in data["edges"]: verts = mesh_buffer.verts - v1 = data["edges"][i]["vertices"][0] - v2 = data["edges"][i]["vertices"][1] + v1 = data["edges"][i]["verts"][0] + v2 = data["edges"][i]["verts"][1] mesh_buffer.edges.new([verts[v1], verts[v2]]) - for p in data["polygons"]: + for p in data["faces"]: verts = [] - for v in data["polygons"][p]["vertices"]: + for v in data["faces"][p]["verts"]: verts.append(mesh_buffer.verts[v]) if len(verts) > 0: f = mesh_buffer.faces.new(verts) - f.material_index = data["polygons"][p]['material_index'] + + uv_layer = mesh_buffer.loops.layers.uv.verify() + + f.material_index = data["faces"][p]['material_index'] + + # UV loading + for i, loop in enumerate(f.loops): + loop_uv = loop[uv_layer] + loop_uv.uv = data["faces"][p]["uv"][i] if target is None: target = bpy.data.meshes.new(data["name"]) mesh_buffer.to_mesh(target) - # LOAD METADATA - # dump_anything.load(target, data) + # mesh_buffer.from_mesh(target) + # 2 - LOAD METADATA + + # uv's + for uv_layer in data['uv_layers']: + target.uv_layers.new(name=uv_layer) + + bevel_layer = mesh_buffer.verts.layers.bevel_weight.verify() + skin_layer = mesh_buffer.verts.layers.skin.verify() + + # for face in mesh_buffer.faces: + + # # Face metadata + # for loop in face.loops: + # loop_uv = loop[uv_layer] + # loop_uv.uv = data['faces'][face.index]["uv"] + + utils.dump_anything.load(target, data) + + # 3 - LOAD MATERIAL SLOTS material_to_load = [] material_to_load = utils.revers(data["materials"]) target.materials.clear() @@ -53,16 +143,12 @@ class BlMesh(ReplicatedDatablock): for m in data["material_list"]: target.materials.append(bpy.data.materials[m]) - - target.id = data['id'] def dump(self, pointer=None): assert(pointer) data = utils.dump_datablock(pointer, 2) - utils.dump_datablock_attibutes( - pointer, ['name', 'polygons', 'edges', 'vertices', 'id'], 6, data) - + data = dump_mesh(pointer, data) # Fix material index m_list = [] for m in pointer.materials: diff --git a/bl_types/bl_scene.py b/bl_types/bl_scene.py new file mode 100644 index 0000000..67bd33c --- /dev/null +++ b/bl_types/bl_scene.py @@ -0,0 +1,55 @@ +import bpy +import mathutils + +from .. import utils +from ..libs.replication.data import ReplicatedDatablock + +class BlScene(ReplicatedDatablock): + def __init__(self, *args, **kwargs): + self.icon = 'SCENE_DATA' + + super().__init__( *args, **kwargs) + + def load(self, data, target): + if target is None: + target = bpy.data.scenes.new(data["name"]) + + # Load other meshes metadata + utils.dump_anything.load(target, data) + + # Load master collection + for object in data["collection"]["objects"]: + if object not in target.collection.objects.keys(): + target.collection.objects.link(bpy.data.objects[object]) + + for object in target.collection.objects.keys(): + if object not in data["collection"]["objects"]: + target.collection.objects.unlink(bpy.data.objects[object]) + + # load collections + # TODO: Recursive link + for collection in data["collection"]["children"]: + if collection not in target.collection.children.keys(): + target.collection.children.link( + bpy.data.collections[collection]) + + for collection in target.collection.children.keys(): + if collection not in data["collection"]["children"]: + target.collection.children.unlink( + bpy.data.collections[collection]) + + + def dump(self, pointer=None): + assert(pointer) + + data = utils.dump_datablock_attibutes( + pointer, ['name', 'collection', 'id', 'camera', 'grease_pencil'], 2) + utils.dump_datablock_attibutes( + pointer, ['collection'], 4, data) + + return data + +bl_id = "scenes" +bl_class = bpy.types.Scene +bl_rep_class = BlScene + diff --git a/libs/replication b/libs/replication index 212dca0..6426517 160000 --- a/libs/replication +++ b/libs/replication @@ -1 +1 @@ -Subproject commit 212dca0825568427ef409a7a9236044ad6f7782b +Subproject commit 64265171f40c15a5cfccfc0f6808f3533402ddb2 diff --git a/ui.py b/ui.py index b9a744d..88f9f77 100644 --- a/ui.py +++ b/ui.py @@ -5,6 +5,11 @@ from . import operators ICONS = {'Image': 'IMAGE_DATA', 'Curve':'CURVE_DATA', 'Client':'SOLO_ON','Collection': 'FILE_FOLDER', 'Mesh': 'MESH_DATA', 'Object': 'OBJECT_DATA', 'Material': 'MATERIAL_DATA', 'Texture': 'TEXTURE_DATA', 'Scene': 'SCENE_DATA','AreaLight':'LIGHT_DATA', 'Light': 'LIGHT_DATA', 'SpotLight': 'LIGHT_DATA', 'SunLight': 'LIGHT_DATA', 'PointLight': 'LIGHT_DATA', 'Camera': 'CAMERA_DATA', 'Action': 'ACTION', 'Armature': 'ARMATURE_DATA', 'GreasePencil': 'GREASEPENCIL'} +PROP_STATES = [ 'ADDED', + 'COMMITED', + 'PUSHED', + 'FETCHED', + 'UP'] class SESSION_PT_settings(bpy.types.Panel): """Settings panel""" bl_idname = "MULTIUSER_SETTINGS_PT_panel" @@ -139,22 +144,23 @@ class SESSION_PT_user(bpy.types.Panel): client_keys = operators.client.list() if client_keys and len(client_keys) > 0: for key in client_keys: - if 'Client' in key[0]: - info = "" - item_box = row.box() - detail_item_box = item_box.row() + pass + # if 'Client' in key[0]: + # info = "" + # item_box = row.box() + # detail_item_box = item_box.row() - username = key[0].split('/')[1] - if username == net_settings.username: - info = "(self)" - # detail_item_box = item_box.row() - detail_item_box.label( - text="{} - {}".format(username, info)) + # username = key[0].split('/')[1] + # if username == net_settings.username: + # info = "(self)" + # # detail_item_box = item_box.row() + # detail_item_box.label( + # text="{} - {}".format(username, info)) - if net_settings.username not in key[0]: - detail_item_box.operator( - "session.snapview", text="", icon='VIEW_CAMERA').target_client = username - row = layout.row() + # if net_settings.username not in key[0]: + # detail_item_box.operator( + # "session.snapview", text="", icon='VIEW_CAMERA').target_client = username + # row = layout.row() else: row.label(text="Empty") @@ -188,12 +194,6 @@ class SESSION_PT_outliner(bpy.types.Panel): row = layout.row() row = layout.row(align=True) - # row.prop(net_settings, "buffer", text="") - # row.prop(net_settings, "add_property_depth", text="") - # add = row.operator("session.add_prop", text="", - # icon="ADD") - # add.property_path = net_settings.buffer - # add.depth = net_settings.add_property_depth area_msg = layout.row() # Property area @@ -209,6 +209,8 @@ class SESSION_PT_outliner(bpy.types.Panel): detail_item_box.label(text="",icon=item.icon) detail_item_box.label(text="{} ".format(item.uuid)) detail_item_box.label(text="{} ".format(item.owner)) + detail_item_box.label(text="{} ".format(PROP_STATES[item.state])) + # right_icon = "DECORATE_UNLOCKED" # if owner == net_settings.username: