Exemplo n.º 1
0
    def _diff(self, struct: T.Object, key: str, prop: T.Property,
              context: Context, diff: Proxy) -> Optional[Delta]:
        from mixer.blender_data.attributes import diff_attribute

        must_replace = False

        data_datablock = struct.data
        if data_datablock is not None:
            dirty_vertex_groups = data_datablock.mixer_uuid in context.visit_state.dirty_vertex_groups
            # Replace the whole Object. Otherwise we would have to merge a DeltaReplace for vertex_groups
            # and a DeltaUpdate for the remaining items
            logger.debug(f"_diff: {struct} dirty vertex group: replace")
            must_replace |= dirty_vertex_groups

        if not must_replace:
            # Parenting with ctrl-P generates a Delta with parent, local_matrix and matrix_parent_inverse.
            # Applying this delta causes a position shift in the parented object. A full replace fixes the problem.
            # Not that parenting with just updating the parent property in the property panel does not cause
            # the same problem
            parent_property = struct.bl_rna.properties["parent"]
            parent_delta = diff_attribute(struct.parent, "parent",
                                          parent_property,
                                          self._data["parent"], context)
            must_replace |= parent_delta is not None

        if must_replace:
            diff.load(struct, context)
            return DeltaReplace(diff)
        else:
            return super()._diff(struct, key, prop, context, diff)
Exemplo n.º 2
0
    def diff(self, datablock: T.ID, key: Union[int, str],
             datablock_property: T.Property,
             context: Context) -> Optional[DeltaReplace]:
        """
        Computes the difference between this proxy and its Blender state.
        """

        if datablock is None:
            return DeltaReplace(DatablockRefProxy())

        value = read_attribute(datablock, key, datablock_property, None,
                               context)
        assert isinstance(value, DatablockRefProxy)
        if value._datablock_uuid != self._datablock_uuid:
            return DeltaReplace(value)
        else:
            return None
Exemplo n.º 3
0
    def _diff(self, struct: T.Mesh, key: str, prop: T.Property,
              context: Context,
              diff: MeshProxy) -> Optional[Union[DeltaUpdate, DeltaReplace]]:

        if self.requires_clear_geometry(struct):
            # If any mesh buffer changes requires a clear geometry on the receiver, the receiver will clear all
            # buffers, including uv_layers and vertex_colors.
            # Resend everything
            diff.load(struct, context)

            # force ObjectProxy._diff to resend the Vertex groups
            context.visit_state.dirty_vertex_groups.add(struct.mixer_uuid)
            return DeltaReplace(diff)
        else:
            if prop is not None:
                context.visit_state.path.append(key)
            try:
                # vertex groups are always replaced as a whole
                mesh_vertex_groups = VertexGroups.from_mesh(
                    struct).to_array_sequence()
                proxy_vertex_groups: ArrayGroup = self._arrays.get(
                    "vertex_groups", [])
                if mesh_vertex_groups != proxy_vertex_groups:
                    diff._arrays["vertex_groups"] = mesh_vertex_groups

                    # force Object update. This requires that Object updates are processed later, which seems to be
                    # the order  they are listed in Depsgraph.updates
                    context.visit_state.dirty_vertex_groups.add(
                        struct.mixer_uuid)

                properties = context.synchronized_properties.properties(struct)
                properties = specifics.conditional_properties(
                    struct, properties)
                for k, member_property in properties:
                    try:
                        member = getattr(struct, k)
                    except AttributeError:
                        logger.warning("diff: unknown attribute ...")
                        logger.warning(
                            f"... {context.visit_state.display_path()}.{k}")
                        continue

                    proxy_data = self._data.get(k)
                    delta = diff_attribute(member, k, member_property,
                                           proxy_data, context)

                    if delta is not None:
                        diff._data[k] = delta

            finally:
                if prop is not None:
                    context.visit_state.path.pop()

            if len(diff._data) or len(diff._arrays):
                return DeltaUpdate(diff)

            return None
    def diff(
        self, collection: T.bpy_prop_collection, key: Union[int, str], collection_property: T.Property, context: Context
    ) -> Optional[Union[DeltaUpdate, DeltaReplace]]:
        """
        Computes the difference between the state of an item tracked by this proxy and its Blender state.

        This proxy tracks a collection of items indexed by string (e.g Scene.render.views) or int.
        The result will be a ProxyDiff that contains a Delta item per added, deleted or updated item

        Args:
            collection; the collection that must be diffed agains this proxy
            key: the name of the collection, to record in the visit path
            collection_property; the property os collection as found in its enclosing object
        """
        sequence = self._sequence
        if len(sequence) == 0 and len(collection) == 0:
            return None

        if specifics.diff_must_replace(collection, sequence, collection_property):
            # A collection cannot be updated because either:
            # - some of its members cannot be updated :
            #   SplineBezierPoints has no API to remove points, so Curve.splines cannot be update and must be replaced
            # - updating the name of members will cause unsolicited renames.
            #   When swapping layers A and B in a GreasePencilLayers, renaming layer 0 into B cause an unsolicited
            #   rename of layer 0 into B.001
            # Send a replacement for the whole collection
            self.load(collection, context)
            return DeltaReplace(self)
        else:
            item_property = collection_property.fixed_type
            diff = self.__class__()

            # items from clear_from index cannot be updated, most often because eir type has changed (e.g
            # ObjectModifier)
            clear_from = specifics.clear_from(collection, sequence, context)

            # run a diff for the head, that can be updated in-place
            for i in range(clear_from):
                delta = diff_attribute(collection[i], i, item_property, sequence[i], context)
                if delta is not None:
                    diff._diff_updates.append((i, delta))

            if specifics.can_resize(collection, context):
                # delete the existing tail that cannot be modified
                diff._diff_deletions = len(sequence) - clear_from

                # add the new tail
                for i, item in enumerate(collection[clear_from:], clear_from):
                    value = read_attribute(item, i, item_property, collection, context)
                    diff._diff_additions.append(DeltaAddition(value))

            if diff._diff_updates or diff._diff_deletions or diff._diff_additions:
                return DeltaUpdate(diff)

        return None
Exemplo n.º 5
0
 def diff(
     self,
     container: Union[T.bpy_prop_collection, T.Struct],
     key: Union[str, int],
     prop: T.Property,
     context: Context,
 ) -> Optional[DeltaUpdate]:
     attr = read_attribute(container, key, prop, None, context)
     if isinstance(attr, NonePtrProxy):
         return None
     return DeltaReplace(attr)
Exemplo n.º 6
0
    def _diff(self, datablock: T.ID, key: Union[int, str], prop: T.Property,
              context: Context, diff: DatablockProxy) -> Optional[Delta]:
        key_blocks = datablock.key_blocks
        key_bocks_property = datablock.bl_rna.properties["key_blocks"]
        key_blocks_proxy = self._data["key_blocks"]
        must_replace = specifics.diff_must_replace(key_blocks,
                                                   key_blocks_proxy._sequence,
                                                   key_bocks_property)
        if must_replace:
            # The Key.key_blocks collection must be replaced, and the receiver must call Object.shape_key_clear(),
            # causing the removal of the Key datablock.

            # Ensure that the whole Key data is available to be reloaded after clear()
            diff.load(datablock, context)
            return DeltaReplace(diff)
        else:
            # this delta is processed by the regular apply
            return super()._diff(datablock, key, prop, context, diff)
Exemplo n.º 7
0
    def diff(self, attribute: Set[Any], unused_key: Union[int, str],
             unused_prop: T.Property,
             unused_context: Context) -> Optional[Delta]:
        """
        Computes the difference between the state of an item tracked by this proxy and its Blender state.

        Args:
            attribute: the set to update (e.g. a the "delimit" attribute of a DecimateModifier instance)
            unused_key: the key that identifies attribute in parent (e.g "delimit")
            unused_prop: the Property of attribute as found in its parent attribute
            unused_context: proxy and visit state
        """
        if set(self.items) == attribute:
            return None

        new_set = SetProxy()
        new_set.items = attribute
        return DeltaReplace(new_set)