Dirty State with Python Generator



  • Hi all,
    I'm trying to get a python generator to only refresh when a source object is dirty, but can't seem to get it to work.
    I move the object, change its geometry, change its parameters, it is never recognized as dirty.
    I tried many different Dirty Flags and I can't get it to work.
    Any idea what I'm doing wrong?

    def main():
        obj = op[c4d.ID_USERDATA,2]
        if obj.IsDirty(c4d.DIRTYFLAGS_ALL):
            print "object is dirty"
            return c4d.BaseObject(c4d.Ocube)
        else:
            return None
    

    python_dirtyState.c4d



  • Hi,

    you probably did not uncheck "optimize cache" in your Python generator object. You also should touch the object after checking its dirty status and handle your cache as you probably do not want your object to turn into a null object. Here is an example:

    import c4d
    
    def main():
        """ Example on how to optimize your cache manually. For this to work you
         obviously have to uncheck 'optimize cache' in your Python generator object
         in the attribute editor.
    
        This script expects you to put an object as a child into the generator
        object. The generator will then return that object.
        """
        # op is predefined as the python generator object.
        first_child = op.GetDown()
        # No child object
        if first_child is None:
            return c4d.BaseList2D(c4d.Onull)
        # Return the child if it is dirty or if op has not build any caches yet.
        if first_child.IsDirty(c4d.DIRTYFLAGS_ALL) or op.GetCache() is None:
            # Consume the dirty flag of the child.
            first_child.Touch()
            # Get a clone of the child, as we cannot insert the same node twice
            # into the document (Cinema has a mono-hierarchical graph).
            clone = first_child.GetClone(c4d.COPYFLAGS_NO_HIERARCHY)
            # Center / align the clone to the Python generator object.
            clone.SetMg(c4d.Matrix())
            print "Build cache"
            return clone
        # Otherwise return the cache.
        else:
            print "Returned cache"
            return op.GetCache()
    

    Cheers
    zipit



  • Hi Zipit, thanks for the reply.

    The Optimized Cache is off.
    I isolated the dirty check code since I couldn't get that part to work.

    Your example works for a child, if I replace it with a link as in my case, then it doesn't work.

    def main():
        linked_object = op[c4d.ID_USERDATA,2]
        # No linked object
        if linked_object is None:
            return c4d.BaseList2D(c4d.Onull)
        # Return the linked object if it is dirty or if op has not build any caches yet.
        if linked_object.IsDirty(c4d.DIRTYFLAGS_ALL) or op.GetCache() is None:
            # Consume the dirty flag of the linked object.
            linked_object.Touch()
            # Get a clone of the linked object, as we cannot insert the same node twice
            # into the document (Cinema has a mono-hierarchical graph).
            clone = linked_object.GetClone(c4d.COPYFLAGS_NO_HIERARCHY)
            # Center / align the clone to the Python generator object.
            clone.SetMg(c4d.Matrix())
            print "Build cache"
            return clone
        # Otherwise return the cache.
        else:
            #print "Returned cache"
            return op.GetCache()
    

    Maybe the python generator can only dirty check its children? Or perhaps the links need special handling?



  • Hi,

    you can dirty check everything, but you have to use a bit more low level approach for your scenario.

    import c4d
    
    """ For this scenario, we need to store the dirty count of the linked object
     somewhere. The problem is, we cannot define an object (variable) with a
     sufficient life time (at least not without some ugly hacks) as we are
     bound to the scope of main().
    
    One solution to store data persistently over multiple executions of a
     scripting object is to store the data in the node attached to that script,
     in our case the Python generator object.
    
    To do that we need a plugin ID (which you can register here in the forum),
     so that we can store that data collision free. REPLACE THIS FOLLOWING ID
     WITH SUCH AN ID.
    """
    ID_PYGEN_DIRTY_CACHE = 10000000
    
    def main():
        linked_object = op[c4d.ID_USERDATA, 2]
        # Get the last cached dirty count and the current dirty count.
        lst_dcount = op[ID_PYGEN_DIRTY_CACHE]
        cur_dcount = linked_object.GetDirty(c4d.DIRTYFLAGS_DATA)
    
        if linked_object is None:
            return c4d.BaseList2D(c4d.Onull)
        # Return the linked object if its dirty count exceeds our cached dirty
        # count or there is no cached dirty count.
        if lst_dcount is None or lst_dcount < cur_dcount:
            # Cache the current dirty count.
            op[ID_PYGEN_DIRTY_CACHE] = cur_dcount
            clone = linked_object.GetClone(c4d.COPYFLAGS_NO_HIERARCHY)
            clone.SetMg(c4d.Matrix())
            print "Built cache"
            return clone
        # Otherwise return the cache.
        else:
            print "Returned cache"
            return op.GetCache()
    

    Cheers
    zipit



  • Thanks a lot for the explanation!
    I replaced the plugin id with a user data and it seems to work ok. Still trying to figure out the matrix on the other thread though.

    Here is the adapted code:

    def main():
        ID_PYGEN_DIRTY_CACHE = op[c4d.ID_USERDATA,3]
        linked_object = op[c4d.ID_USERDATA, 2]
        # Get the last cached dirty count and the current dirty count.
        lst_dcount = ID_PYGEN_DIRTY_CACHE
        cur_dcount = linked_object.GetDirty(c4d.DIRTYFLAGS_ALL)
    
        if linked_object is None:
            return c4d.BaseList2D(c4d.Onull)
        # Return the linked object if its dirty count exceeds our cached dirty
        # count or there is no cached dirty count.
        if lst_dcount is None or lst_dcount < cur_dcount or op.GetCache() is None:
            # Cache the current dirty count.
            op[c4d.ID_USERDATA,3] = cur_dcount
            clone = linked_object.GetClone(c4d.COPYFLAGS_NO_HIERARCHY)
            clone.SetMg(c4d.Matrix())
            print "Built cache"
            return clone
        # Otherwise return the cache.
        else:
            print "Returned cache"
            return op.GetCache()
    

    And the file:
    python_dirtyState_0001.c4d


Log in to reply