Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Dirty State with Python Generator

    Cinema 4D SDK
    python sdk
    2
    5
    1.0k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • orestiskonO
      orestiskon
      last edited by r_gigante

      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

      1 Reply Last reply Reply Quote 1
      • ferdinandF
        ferdinand
        last edited by ferdinand

        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

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • orestiskonO
          orestiskon
          last edited by orestiskon

          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?

          1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand
            last edited by ferdinand

            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

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 1
            • orestiskonO
              orestiskon
              last edited by

              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

              1 Reply Last reply Reply Quote 0
              • First post
                Last post