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

    How to allocate a gradient in Python?

    PYTHON Development
    0
    22
    12.5k
    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.
    • H
      Helper
      last edited by

      On 08/06/2013 at 05:23, xxxxxxxx wrote:

      @littledevil:
      Thank you, so my first idea was correct indeed.

      So it is:

      gradient = c4d.Gradient()
      

      But by the way, be careful, of course you have to respect the case sensitivity! Wink

      The problem was in fact introduced in another part of the source code and I only thought my allocation failed. 😄

      @ScottA:
      Here it is (it's nearly complete but there are some problems with the Output() left) :

        
      #############################################################  
      ## CINEMA 4D Python Gradient Shader                        ##  
      #############################################################  
      ## (c) 2013 Thomas Chen, all rights reserved               ##  
      #############################################################  
      ## Python-Gradient.pyp                                     ##  
      #############################################################  
        
      import os  
      import math  
        
      import c4d  
      from c4d import plugins, bitmaps, utils, storage, gui  
      from c4d.utils.noise import Turbulence  
        
      #warning Please obtain your own plugin ID from http://www.plugincafe.com  
      PLUGIN_ID = 1000001  
        
        
      class SDKGradientClass(plugins.ShaderData) :  
        
        cycle = False  
        mode = 0  
        angle = 0.0  
        c = [0.0, 0.0, 0.0, 0.0]        # maybe not optimal?  
        sa = 0.0  
        ca = 0.0      
        
        turbulence = 0.0  
        octaves = 5.0  
        scale = 1.0  
        freq = 1.0  
        absolute = False  
        
        gradient = c4d.Gradient()  
        
        
        def Init(self, node) :  
            #Called when a new instance of the node plugin has been allocated.  
        
            k1_col = c4d.Vector(0.0, 0.0, 1.0)  
            k1_pos = 0.0  
        
            k2_col = c4d.Vector(1.0, 1.0, 1.0)  
            k2_pos = 1.0  
        
            self.gradient.InsertKnot(col = k1_col, pos = k1_pos)  
            self.gradient.InsertKnot(col = k2_col, pos = k2_pos)  
        
            node[c4d.SDKGRADIENTSHADER_COLOR] = self.gradient  
            node[c4d.SDKGRADIENTSHADER_CYCLE] = self.cycle  
            node[c4d.SDKGRADIENTSHADER_MODE] = self.mode  
            node[c4d.SDKGRADIENTSHADER_ANGLE] = self.angle  
        
            node[c4d.SDKGRADIENTSHADER_TURBULENCE] = self.turbulence  
            node[c4d.SDKGRADIENTSHADER_OCTAVES] = self.octaves  
            node[c4d.SDKGRADIENTSHADER_SCALE] = self.scale  
            node[c4d.SDKGRADIENTSHADER_FREQ] = self.freq  
            node[c4d.SDKGRADIENTSHADER_ABSOLUTE] = self.absolute  
        
            return True  
        
        
        def InitRender(self, sh, irs) :  
            #Precalculate any data for rendering.  
        
            self.mode = sh[c4d.SDKGRADIENTSHADER_MODE]  
            self.angle = sh[c4d.SDKGRADIENTSHADER_ANGLE]  
            self.cycle = sh[c4d.SDKGRADIENTSHADER_CYCLE]  
            self.turbulence = sh[c4d.SDKGRADIENTSHADER_TURBULENCE]  
            self.octaves = sh[c4d.SDKGRADIENTSHADER_OCTAVES]  
            self.scale = sh[c4d.SDKGRADIENTSHADER_SCALE]  
            self.freq = sh[c4d.SDKGRADIENTSHADER_FREQ]  
            self.absolute = sh[c4d.SDKGRADIENTSHADER_ABSOLUTE]  
            self.gradient = sh[c4d.SDKGRADIENTSHADER_COLOR]  
      #        if !self.gradient or !self.gradient.InitRender(irs) : return c4d.INITRENDERRESULT_OUTOFMEMORY            # SYNTAX ERROR! "if !var" doesn't exist in Python! But it's "just" a safety check and it should work without it.  
        
            self.sa, self.ca = utils.SinCos(self.angle)  
        
            for i in range (0, 4) :  
                self.c[i] = 0.0  
                k = self.gradient.GetKnot(i)        # maybe Gradient.GetKnot(index) is wrong here, but Gradient.GetRenderKnot(index) seem not to exist in the Python SDK.  
                if (k) : self.c[i] = k['col']  
        
            return 0  
        
        
        def FreeRender(self, sh) :  
            #Free any resources used for the precalculated data from InitRender()  
            if (self.gradient) : self.gradient.FreeRender()  
            self.gradient = None  
        
        
        def Output(self, sh, cd) :  
            #Called for each point of the visible surface of a shaded object. Here you should calculate and return the channel color for the point cd.p.  
        
            p = cd.p  
            r = 0.0  
        
            if (self.turbulence > 0.0) :  
                scl = 5.0 * self.scale  
                tt = cd.t * self.freq * 0.3  
        
                res = c4d.Vector(Turbulence(p * scl, tt, self.octaves, True), Turbulence((p+c4d.Vector(0.34, 13.0, 2.43)) * scl, tt, self.octaves, True), 0.0)  
        
                if self.absolute:  
                    p.x = utils.MixNum(p.x, res.x, self.turbulence)  
                    p.y = utils.MixNum(p.y, res.y, self.turbulence)  
                else:  
                    p.x += (res.x - 0.5) * self.turbulence  
                    p.y += (res.y - 0.5) * self.turbulence  
        
            #rotation  
            p.x -= 0.5  
            p.y -= 0.5  
        
            xx = self.ca * p.x - self.sa * p.y + 0.5  
            yy = self.sa * p.x + self.ca * p.y + 0.5  
        
            p.x = xx  
            p.y = yy  
        
            if (self.mode <= c4d.SDKGRADIENTSHADER_MODE_CORNER) and self.cycle and (cd.texflag & c4d.TEX_TILE) :  
                if cd.texflag is c4d.TEX_MIRROR:  
                    p.x = p.x % 2.0  
                    if p.x >= 1.0: p.x = 2.0 - p.x  
        
                    p.y = p.y % 2.0  
                    if p.y >= 1.0: p.y = 2.0 - p.y  
        
                else:  
                    p.x = p.x % 1.0  
                    p.y = p.y % 1.0  
        
            if self.mode is c4d.SDKGRADIENTSHADER_MODE_U:  
                r = p.x  
        
            elif self.mode is c4d.SDKGRADIENTSHADER_MODE_V:  
                r = 1.0 - p.y  
        
            elif self.mode is c4d.SDKGRADIENTSHADER_MODE_DIAGONAL:  
                r  = (p.x + p.y) * 0.5  
         
            elif self.mode is c4d.SDKGRADIENTSHADER_MODE_RADIAL:  
                p.x -= 0.5  
                p.y -= 0.5  
                if p.x == 0.0: p.x = 0.00001  
        
                angle = math.atan(p.y / p.x)  
                if p.x < 0.0: angle += math.pi  
                if angle < 0.0: angle += (math.pi * 2.0)  
                r  = angle / (math.pi * 2.0)  
        
            elif self.mode is c4d.SDKGRADIENTSHADER_MODE_CIRCULAR:  
                p.x -= 0.5  
                p.y -= 0.5  
                r = math.sqrt(p.x * p.x + p.y * p.y) * 2.0  
        
            elif self.mode is c4d.SDKGRADIENTSHADER_MODE_BOX:  
                p.x = abs(p.x - 0.5)  
                p.y = abs(p.y - 0.5)  
                r = max(p.x, p.y) * 2.0  
        
            elif self.mode is c4d.SDKGRADIENTSHADER_MODE_STAR:  
                p.x = abs(p.x - 0.5) - 0.5  
                p.y = abs(p.y - 0.5) - 0.5  
                r = math.sqrt(p.x * p.x + p.y * p.y) * 1.4142  
        
            elif self.mode is c4d.SDKGRADIENTSHADER_MODE_CORNER:  
                cx = utils.FCut(p.x, 0.0, 1.0)  
                ca = utils.MixVec(self.c[0], self.c[1], cx)  
                cb = utils.MixVec(self.c[2], self.c[3], cx)  
                  
                return utils.MixVec(ca, cb, utils.FCut(p.y, 0.0, 1.0))  
        
            return self.gradient.CalcGradientPixel(utils.FCut(r, 0.0, 1.0))         # something is wrong here, because "self.gradient" seems black end empty and so is of course the output  
        
        
      def RegisterSDKGradientClass() :  
          
        fn = os.path.join(os.path.dirname(__file__), "res", "gradienttypes.tif")  
        bmp = bitmaps.BaseBitmap()  
        if c4d.IMAGERESULT_OK != bmp.InitWith(fn)[0]: return false  
        
        gui.RegisterIcon(200000135, bmp, 0*32, 0, 32, 32)  
        gui.RegisterIcon(200000136, bmp, 1*32, 0, 32, 32)  
        gui.RegisterIcon(200000137, bmp, 2*32, 0, 32, 32)  
        gui.RegisterIcon(200000138, bmp, 3*32, 0, 32, 32)  
        gui.RegisterIcon(200000139, bmp, 4*32, 0, 32, 32)  
        gui.RegisterIcon(200000140, bmp, 5*32, 0, 32, 32)  
        gui.RegisterIcon(200000141, bmp, 6*32, 0, 32, 32)  
        gui.RegisterIcon(200000142, bmp, 7*32, 0, 32, 32)  
          
        return plugins.RegisterShaderPlugin(PLUGIN_ID, "Python Gradient", 0, SDKGradientClass, "xsdkgradient", 0)  
        
      if __name__ == '__main__':  
        RegisterSDKGradientClass()  
        
      

      It is (should be) as close as I was able to do it on the C++ gradient shader example.
      And also the resources are the same, so you could take it directly from the C++ SDK example.

      The problems, as far as I could locate them are marked in the source code.
      Maybe one of you could figure them out and tell me how to fix them completely! 😉

      Also if you see something what could/should have been done in a other/better way, please tell me.
      As I told before, I'm just learning the whole Python stuff. 😉

      Kind regards,
      Tom

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 08/06/2013 at 05:31, xxxxxxxx wrote:

        Python doesn't have a ! operator, it's "not".

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 08/06/2013 at 08:33, xxxxxxxx wrote:

          The problem I'm having isn't the code. It's with the layout structure of a shader plugin.
          For some reason. I cannot get the plugin to load the Gradient gizmo from the .res file.

          I've got the correct .res file name in the registration. Everything has an ID#. And I have all the text constant assigned to them in the .str file.
          I don't usually have much trouble setting up a plugin's framework. But this one is being real P.I.A. for some reason.

          Also. None of the shader plugin examples in the python SDK use a .res file for me to see what I'm doing wrong. I hate it when they do that and don't provide a .res based example.
          That's really annoying.

          -ScottA

          Edit:
          Are you guys using R14?
          The gradient gimo refuses to show up in my plugin. And I'm starting to wonder if the reason I can't get it to show up is because it's not supported in R13?

          Here is my .res file:

          CONTAINER myshader  
          {  
            NAME myshader;  
            INCLUDE Mpreview;  //The preview window gizmo... Works fine  
            INCLUDE Xbase;     //The Blurr sliders gizmos... works fine  
            
            
            GRADIENT MY_GRADIENT { ICC_BASEDOCUMENT; }  //<--does not work!!!!  
            
          }
          

          I'm banging my head trying to figure out why this stupid thing will not show up.

          -ScottA

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 08/06/2013 at 11:24, xxxxxxxx wrote:

            Doh!
            I figured out the problem.
            This has to in the .res file for the gradient gizmo to show up:   INCLUDE xsdkgradient;

            -ScottA

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 08/06/2013 at 11:51, xxxxxxxx wrote:

              Originally posted by xxxxxxxx

              Python doesn't have a ! operator, it's "not".

              Or you can do it with exception handling (with try: and except ) as far as I know.
              I'm not just yet sure what would be the best solution for this situation. 😄

              Originally posted by xxxxxxxx

              The problem I'm having isn't the code. It's with the layout structure of a shader plugin.
              For some reason. I cannot get the plugin to load the Gradient gizmo from the .res file.

              I've got the correct .res file name in the registration. Everything has an ID#. And I have all the text constant assigned to them in the .str file.
              I don't usually have much trouble setting up a plugin's framework. But this one is being real P.I.A. for some reason.

              Also. None of the shader plugin examples in the python SDK use a .res file for me to see what I'm doing wrong. I hate it when they do that and don't provide a .res based example.
              That's really annoying.

              -ScottA

              Edit:
              Are you guys using R14?
              The gradient gimo refuses to show up in my plugin. And I'm starting to wonder if the reason I can't get it to show up is because it's not supported in R13?

              Here is my .res file:

              CONTAINER myshader  
              {  
                NAME myshader;  
                INCLUDE Mpreview;  //The preview window gizmo... Works fine  
                INCLUDE Xbase;     //The Blurr sliders gizmos... works fine  
               
               
                GRADIENT MY_GRADIENT { ICC_BASEDOCUMENT; }  //<--does not work!!!!  
               
              }
              

              I'm banging my head trying to figure out why this stupid thing will not show up.

              -ScottA

              Might be a problem with the symbol cache file(s) from C4D where it stores all the keywords from C.O.F.F.E.E. and Python plugins if they had been recogniced by C4D earlier.

              And that can cause serious trouble when you are under development and make changes to the resource files. And yes, it's quite tricky to find out. I know what I'm talking about. 😉

              For this reason I made me a little script for my development c4d installation(s) (yes, I use seperate copies of my C4D Releases configured for development purposes only) that delete this symbolcache file at every startup (it will become automatically recreated by C4D itself when it doesn't exist anymore but now with the fresh and current valid values ).

              The script have to be named "python_init.py" and it belongs to "{USER_FOLDER}/prefs/python/" to be executed on startup of CINEMA 4D.

              And here is mine: 😉

                
              ##################################  
              ## python_init.py               ##  
              ##################################  
              ## created 2013 by Thomas Chen  ##  
              ##################################  
                
              import c4d  
              import os  
                
              #================================================================================  
              # Removes the symbol cache file in case it exist.                           #====  
              # (THIS IS FOR DEVELOPMENT PURPOSES ONLY, NOT FOR REGULAR USE OF C4D!!!)    #====  
              #================================================================================  
              path = c4d.storage.GeGetStartupWritePath() + "\prefs\symbolcache"           #====  
              if os.path.exists(path) :                                                    #====  
                print path                                                              #====  
                os.remove(path)                                                         #====  
                print "symbolcache removed!"                                            #====  
              else: print "there is no symbolcache!"                                      #====  
              #================================================================================  
              #================================================================================  
              

              Till now I just handle the file "symbolcache" that way.

              There is also a "directorycache" file, that could also be deleted.
              But I hadn't recognize problems related to it yet.

              And I can remeber a "coffeesymbolcache" file but I guess that was just the name in earlier releases before c4d had Python support too.

              Feel free to use it and I hope it helps. 🙂

              Kind regards,
              Tom

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 08/06/2013 at 13:02, xxxxxxxx wrote:

                Thanks Tom.
                But I figured it out. And got it working.

                I looked at your code.
                You did a good job converting it to Python. But the problem you're having with the turbulence looks like a conversion problem from C++ Python.
                I guess you can't use commas with multiple variables the same way in Python as it's written in C++.

                Try this code out and you should get a result from the turbulence gizmo value:

                      
                Comment out this sucker  
                #res = c4d.Vector(Turbulence(p * scl, tt, self.octaves, True), Turbulence((p+c4d.Vector(0.34, 13.0, 2.43)) * scl, tt, self.octaves, True), 0.0)  
                  
                And use this instead:  
                  turb = Turbulence(p * scl, self.octaves, True)  
                  res = c4d.Vector(turb, 0, 0 )
                

                That should give you a similar kind of turbulence result as the C++ plugin. But not exactly though.
                What I would do is write those three turbulence's out as three separate variables. Doing them one at a time. And watching the python console for errors.

                Then when you have them all working without any errors.
                Plug them into your res variable. Like this: res = c4d.Vector(turb1, turb2, turb3)

                -ScottA

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 08/06/2013 at 16:27, xxxxxxxx wrote:

                  Originally posted by xxxxxxxx

                  Thanks Tom.
                  But I figured it out. And got it working.

                  Originally posted by xxxxxxxx

                  This has to in the .res file for the gradient gizmo to show up:   INCLUDE xsdkgradient;

                  Sorry, but I think there you are mistaken.

                  Okay I indeed used the xsdkgradient.h, xsdkgradient.res and xsdkgradient.str from the original C++ SDK gradient example, but very well-considered and only to stay as close as possible to that certain example.
                  So that it will be as comparable as it gets in the end.

                  But it is absolutely not required for that task.
                  You could also build up the whole resources stuff by yourself.

                  It really sounds to me like the symbol cache problem I mentioned above!

                  So please do me a favor, search for the "symbolcache" file in the C4D "{USER_FOLDER}/prefs/", delete it and then try your old method without the extra include again.

                  At least try it and then tell me about it, okay? 😉
                  (Of course there could also be another problem, but I'm quite sure that's it in your case, really!)

                  Originally posted by xxxxxxxx

                  I looked at your code.
                  You did a good job converting it to Python.

                  Oh, thank you very much! 😊

                  Originally posted by xxxxxxxx

                  But the problem you're having with the turbulence looks like a conversion problem from C++ Python.
                  I guess you can't use commas with multiple variables the same way in Python as it's written in C++.

                  Hey, great find! You're absolutely right. 👏
                  As a matter of fact I hadn't checked and compared the parameter list of this function implementation in both coding languages but merely changed the syntax to Python.
                  That was a bit careless from me and indeed there is a little difference. 😂

                  That's the original C++ code line:

                    
                  res = Vector(Turbulence(p*scl,tt,gdata.octaves,TRUE),Turbulence((p+Vector(0.34,13.0,2.43))*scl,tt,gdata.octaves,TRUE),0.0);  
                  

                  And so it have to look like in Python:

                    
                  res = c4d.Vector(Turbulence(p * scl, self.octaves, True, tt), Turbulence((p+c4d.Vector(0.34, 13.0, 2.43)) * scl, self.octaves, True, tt), 0.0)  
                  

                  Or to make it short: the time parameter of the C4DNoise.Turbulence() function simply has to jump from the middle of the list to the end. 😉
                   
                  But of course that wasn't the reason for the main problem.
                  The real trouble came from the one line that I temporarily commented out and dismissed overhasty as "just" a safety check.

                  So yes, the code is complete now and works, as it should. 🙂

                  Unfortunately I have to admit, that I still couldn't figure out what exactly this line is for and why it's so essential?
                  Obviously the important element here have to be the "gradient.InitRender(irs)" because the gradient itself should normally always be true.

                  But as I said, it's so far complete now and should be working as expected (or at least I hope so 😉) and so here it is again: 🙂

                    
                  #############################################################  
                  ## CINEMA 4D Python Gradient Shader                        ##  
                  ## [1:1 conversion from the analogical C++ SDK example]    ##  
                  ## [originally done by the MAXON Computer GmbH]            ##  
                  #############################################################  
                  ## (c) 2013 Thomas Chen, all rights reserved               ##  
                  #############################################################  
                  ## Python-Gradient.pyp                                     ##  
                  #############################################################  
                    
                  import os  
                  import math  
                    
                  import c4d  
                  from c4d import plugins, bitmaps, utils, storage, gui  
                  from c4d.utils.noise import Turbulence  
                    
                  #warning Please obtain your own plugin ID from http://www.plugincafe.com  
                  PLUGIN_ID = 1000001  
                    
                    
                  class SDKGradientClass(plugins.ShaderData) :  
                    
                    cycle = False  
                    mode = 0  
                    angle = 0.0  
                    c = [0.0, 0.0, 0.0, 0.0]        # maybe not optimal?  
                    sa = 0.0  
                    ca = 0.0      
                    
                    turbulence = 0.0  
                    octaves = 5.0  
                    scale = 1.0  
                    freq = 1.0  
                    absolute = False  
                    
                    gradient = c4d.Gradient()  
                    
                    
                    def Init(self, node) :  
                        #Called when a new instance of the node plugin has been allocated.  
                    
                        k1_col = c4d.Vector(0.0, 0.0, 1.0)  
                        k1_pos = 0.0  
                    
                        k2_col = c4d.Vector(1.0, 1.0, 1.0)  
                        k2_pos = 1.0  
                    
                        self.gradient.InsertKnot(col = k1_col, pos = k1_pos)  
                        self.gradient.InsertKnot(col = k2_col, pos = k2_pos)  
                    
                        node[c4d.SDKGRADIENTSHADER_COLOR] = self.gradient  
                        node[c4d.SDKGRADIENTSHADER_CYCLE] = self.cycle  
                        node[c4d.SDKGRADIENTSHADER_MODE] = self.mode  
                        node[c4d.SDKGRADIENTSHADER_ANGLE] = self.angle  
                    
                        node[c4d.SDKGRADIENTSHADER_TURBULENCE] = self.turbulence  
                        node[c4d.SDKGRADIENTSHADER_OCTAVES] = self.octaves  
                        node[c4d.SDKGRADIENTSHADER_SCALE] = self.scale  
                        node[c4d.SDKGRADIENTSHADER_FREQ] = self.freq  
                        node[c4d.SDKGRADIENTSHADER_ABSOLUTE] = self.absolute  
                    
                        return True  
                    
                    
                    def InitRender(self, sh, irs) :  
                        #Precalculate any data for rendering.  
                    
                        self.mode = sh[c4d.SDKGRADIENTSHADER_MODE]  
                        self.angle = sh[c4d.SDKGRADIENTSHADER_ANGLE]  
                        self.cycle = sh[c4d.SDKGRADIENTSHADER_CYCLE]  
                        self.turbulence = sh[c4d.SDKGRADIENTSHADER_TURBULENCE]  
                        self.octaves = sh[c4d.SDKGRADIENTSHADER_OCTAVES]  
                        self.scale = sh[c4d.SDKGRADIENTSHADER_SCALE]  
                        self.freq = sh[c4d.SDKGRADIENTSHADER_FREQ]  
                        self.absolute = sh[c4d.SDKGRADIENTSHADER_ABSOLUTE]  
                        self.gradient = sh[c4d.SDKGRADIENTSHADER_COLOR]  
                        if (not self.gradient) or (not self.gradient.InitRender(irs)) : return c4d.INITRENDERRESULT_OUTOFMEMORY  
                          
                        self.sa, self.ca = utils.SinCos(self.angle)  
                    
                        for i in range (0, 4) :  
                            self.c[i] = 0.0  
                            k = self.gradient.GetKnot(i)        # here I had to use "Gradient.GetKnot(index)" because there is no "Gradient.GetRenderKnot(index)" in the Python SDK.  
                            if (k) : self.c[i] = k['col']  
                    
                        return 0  
                    
                    
                    def FreeRender(self, sh) :  
                        #Free any resources used for the precalculated data from InitRender()  
                        if (self.gradient) : self.gradient.FreeRender()  
                        self.gradient = None  
                    
                    
                    def Output(self, sh, cd) :  
                        #Called for each point of the visible surface of a shaded object. Here you should calculate and return the channel color for the point cd.p.  
                    
                        p = cd.p  
                        r = 0.0  
                    
                        if (self.turbulence > 0.0) :  
                            scl = 5.0 * self.scale  
                            tt = cd.t * self.freq * 0.3  
                    
                            res = c4d.Vector(Turbulence(p * scl, self.octaves, True, tt), Turbulence((p+c4d.Vector(0.34, 13.0, 2.43)) * scl, self.octaves, True, tt), 0.0)  
                    
                            if self.absolute:  
                                p.x = utils.MixNum(p.x, res.x, self.turbulence)  
                                p.y = utils.MixNum(p.y, res.y, self.turbulence)  
                            else:  
                                p.x += (res.x - 0.5) * self.turbulence  
                                p.y += (res.y - 0.5) * self.turbulence  
                    
                        #rotation  
                        p.x -= 0.5  
                        p.y -= 0.5  
                    
                        xx = self.ca * p.x - self.sa * p.y + 0.5  
                        yy = self.sa * p.x + self.ca * p.y + 0.5  
                    
                        p.x = xx  
                        p.y = yy  
                    
                        if (self.mode <= c4d.SDKGRADIENTSHADER_MODE_CORNER) and self.cycle and (cd.texflag & c4d.TEX_TILE) :  
                            if cd.texflag is c4d.TEX_MIRROR:  
                                p.x = p.x % 2.0  
                                if p.x >= 1.0: p.x = 2.0 - p.x  
                    
                                p.y = p.y % 2.0  
                                if p.y >= 1.0: p.y = 2.0 - p.y  
                    
                            else:  
                                p.x = p.x % 1.0  
                                p.y = p.y % 1.0  
                    
                        if self.mode is c4d.SDKGRADIENTSHADER_MODE_U:  
                            r = p.x  
                    
                        elif self.mode is c4d.SDKGRADIENTSHADER_MODE_V:  
                            r = 1.0 - p.y  
                    
                        elif self.mode is c4d.SDKGRADIENTSHADER_MODE_DIAGONAL:  
                            r = (p.x + p.y) * 0.5  
                    
                        elif self.mode is c4d.SDKGRADIENTSHADER_MODE_RADIAL:  
                            p.x -= 0.5  
                            p.y -= 0.5  
                            if p.x == 0.0: p.x = 0.00001  
                    
                            angle = math.atan(p.y / p.x)  
                            if p.x < 0.0: angle += math.pi  
                            if angle < 0.0: angle += (math.pi * 2.0)  
                            r = angle / (math.pi * 2.0)  
                    
                        elif self.mode is c4d.SDKGRADIENTSHADER_MODE_CIRCULAR:  
                            p.x -= 0.5  
                            p.y -= 0.5  
                            r = math.sqrt(p.x * p.x + p.y * p.y) * 2.0  
                    
                        elif self.mode is c4d.SDKGRADIENTSHADER_MODE_BOX:  
                            p.x = abs(p.x - 0.5)  
                            p.y = abs(p.y - 0.5)  
                            r = max(p.x, p.y) * 2.0  
                    
                        elif self.mode is c4d.SDKGRADIENTSHADER_MODE_STAR:  
                            p.x = abs(p.x - 0.5) - 0.5  
                            p.y = abs(p.y - 0.5) - 0.5  
                            r = math.sqrt(p.x * p.x + p.y * p.y) * 1.4142  
                    
                        elif self.mode is c4d.SDKGRADIENTSHADER_MODE_CORNER:  
                            cx = utils.FCut(p.x, 0.0, 1.0)  
                            ca = utils.MixVec(self.c[0], self.c[1], cx)  
                            cb = utils.MixVec(self.c[2], self.c[3], cx)  
                              
                            return utils.MixVec(ca, cb, utils.FCut(p.y, 0.0, 1.0))  
                    
                        return self.gradient.CalcGradientPixel(utils.FCut(r, 0.0, 1.0))  
                    
                    
                  def RegisterSDKGradientClass() :  
                      
                    fn = os.path.join(os.path.dirname(__file__), "res", "gradienttypes.tif")  
                    bmp = bitmaps.BaseBitmap()  
                    if c4d.IMAGERESULT_OK != bmp.InitWith(fn)[0]: return False  
                    
                    gui.RegisterIcon(200000135, bmp, 0*32, 0, 32, 32)  
                    gui.RegisterIcon(200000136, bmp, 1*32, 0, 32, 32)  
                    gui.RegisterIcon(200000137, bmp, 2*32, 0, 32, 32)  
                    gui.RegisterIcon(200000138, bmp, 3*32, 0, 32, 32)  
                    gui.RegisterIcon(200000139, bmp, 4*32, 0, 32, 32)  
                    gui.RegisterIcon(200000140, bmp, 5*32, 0, 32, 32)  
                    gui.RegisterIcon(200000141, bmp, 6*32, 0, 32, 32)  
                    gui.RegisterIcon(200000142, bmp, 7*32, 0, 32, 32)  
                    
                    return plugins.RegisterShaderPlugin(PLUGIN_ID, "Python Gradient", 0, SDKGradientClass, "xsdkgradient", 0)  
                    
                  if __name__ == '__main__':  
                    RegisterSDKGradientClass()  
                    
                  

                  Kind regards,
                  Tom

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 08/06/2013 at 17:39, xxxxxxxx wrote:

                    Originally posted by xxxxxxxx

                    It really sounds to me like the symbol cache problem I mentioned above!
                    So please do me a favor, search for the "symbolcache" file in the C4D "{USER_FOLDER}/prefs/", delete it and then try your old method without the extra include again.
                    At least try it and then tell me about it, okay? 😉

                    Nope. Not a symbol cache problem.
                    I deleted it and tested it. And the Gradient gizmo still does not show up without this: INCLUDE xsdkgradient;

                    I honestly think that's the correct way it's supposed to work though.
                    For example. Look at the other entries in my .res file:
                      INCLUDE Mpreview;         //The preview window gizmo
                      INCLUDE Xbase;            //The Blurr sliders gizmos

                    Without those in my .res file. Those two gizmos do not show up either.
                    I have no idea how you are able to get your gizmos to show up without #Including them in your .res file. But I suspect that you are doing that in some other place in your plugin.

                    I guess it doesn't really matter though. It works and that's all that really matters.
                    Thanks again for posting your code. It saved me the trouble of making one from scratch.

                    Vielen Dank,
                    -ScottA

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 08/06/2013 at 22:15, xxxxxxxx wrote:

                      I just figured out why I had to use INCLUDE xsdkgradient; in my .res file.

                      Your code is not creating a truly unique instance of the gradient class. And you are still using the same IDs from the instance created by the the example in the SDK.
                      That's why it works for me when I use the Include in my .res file.

                      Just writing this code isn't enough to create unique instance: gradient = c4d.Gradient()
                      We also have to set the type of gui as: CUSTOMDATATYPE_GRADIENT.
                      And we also have to somehow assign our own personal ID for the gradient instance in the .res file to this specific instance.
                      Doing this does not work: node[c4d.MY_GRADIENT] = self.gradient

                      This is the  C++ code that does that. And needs to be translated into Python to create a truly unique gradient instance:

                          BaseContainer *data = ((BaseShader* )node)->GetDataInstance();  
                        
                        AutoAlloc<Gradient> gradient;     //Creates a new gradient instance  
                        if (!gradient) return FALSE;  
                        
                        //This is where we assign the gradient instance with our own  personal ID in the .res file  
                        //This is not in your python version..You're still using the gradient instance the C++ SDK created  
                        data->SetData(c4d.SDKGRADIENTSHADER_COLOR, GeData(CUSTOMDATATYPE_GRADIENT,gradient));
                      

                      Your first question was never really answered.
                      We still need to know how to create a unique instance of a gradient gizmo.

                      -ScottA

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 09/06/2013 at 09:52, xxxxxxxx wrote:

                        Hi Scott,

                        as the whole xsdkgradient thing is also just a plugin and not a part of C4D itself, I think it's not a very safe idea to make includes from it, as they have to fail for sure, if you don't have this sdk examples installed in C4D!

                        With "Mpreview" and "Xbase" it is different.
                        That are elements that all shaders (normally should) have!
                        So it wouldn't be very reasonable (and also against the OOP idea! 😉) to write your own stuff for it instead to include these basic elements, that are available from the C4D API.

                        Of course this might be also true for a gradient, if you need (and want to use) a c4d standard gradient anywhere for a plugin.
                        But therefore you'd have to include "x sla gradient" and never ever "x sdk gradient"!

                        And in this case the keyword for the gradient itself would be:

                        c4d.SLA_GRADIENT_GRADIENT
                        

                        By the way, here are the elements for it from the "xslagradient.h":

                          
                        #ifndef _Xslagradient_H_  
                        #define _Xslagradient_H_  
                          
                        enum  
                        {  
                          XSLAGradient                          = 1000,  
                          
                          SLA_GRADIENT_TYPE                     = 1001,   // LONG  
                          SLA_GRADIENT_TYPE_2D_U              = 2000,  
                          SLA_GRADIENT_TYPE_2D_V,  
                          SLA_GRADIENT_TYPE_2D_DIAG,  
                          SLA_GRADIENT_TYPE_2D_RAD,  
                          SLA_GRADIENT_TYPE_2D_CIRC,  
                          SLA_GRADIENT_TYPE_2D_BOX,  
                          SLA_GRADIENT_TYPE_2D_STAR,  
                          SLA_GRADIENT_TYPE_2D_FOUR_CORNER,  
                          SLA_GRADIENT_TYPE_3D_LINEAR,  
                          SLA_GRADIENT_TYPE_3D_CYLINDRICAL,  
                          SLA_GRADIENT_TYPE_3D_SPHERICAL,  
                          
                          SLA_GRADIENT_CYCLE                    = 1002,   // Bool  
                          SLA_GRADIENT_START                    = 1003,   // Vector  
                          SLA_GRADIENT_END                      = 1004,   // Vector  
                          SLA_GRADIENT_RADIUS                   = 1005,   // Real  
                          SLA_GRADIENT_SPACE                    = 1006,   // LONG  
                          SLA_GRADIENT_SPACE_TEXTURE          = 2020,  
                          SLA_GRADIENT_SPACE_OBJECT,  
                          SLA_GRADIENT_SPACE_WORLD,  
                          SLA_GRADIENT_SPACE_CAMERA,  
                          SLA_GRADIENT_SPACE_SCREEN,  
                          SLA_GRADIENT_SPACE_RASTER,  
                          
                          SLA_GRADIENT_TURBULENCE               = 1011, // real  
                          SLA_GRADIENT_OCTAVES                  = 1012, // real  
                          SLA_GRADIENT_SCALE                    = 1013, // real  
                          SLA_GRADIENT_FREQ                     = 1014, // real  
                          SLA_GRADIENT_SEED                                            = 1017, // long  
                          SLA_GRADIENT_ABSOLUTE                 = 1015, // bool  
                          SLA_GRADIENT_ANGLE                    = 1016, // real  
                          
                          SLA_GRADIENT_GRADIENT                 = 1007,   // Gradient  
                            
                          SLA_GRADIENT_DUMMY_  
                        };  
                          
                        #endif // _Xslagradient_H_  
                        

                        You can find it here: {CINEMA 4D main directory}\resource\modules\sla\res\description\

                        Okay, now here is a very basic gradient shader example by me, reduced to the minimum without any dependencies to the xsdkgradient (or the xslagradient! 😉) and with all the resource files for it:

                        py-gradient.pyp

                          
                        import c4d  
                        from c4d import plugins, utils  
                          
                          
                        class PyGradient(plugins.ShaderData) :  
                          
                          gradient = c4d.Gradient()  
                          
                          
                          def Init(self, node) :  
                              self.gradient.InsertKnot(col = c4d.Vector(0.0, 0.0, 0.0), pos = 0.0)  
                              self.gradient.InsertKnot(col = c4d.Vector(1.0, 1.0, 1.0), pos = 1.0)  
                              node[c4d.PY_GRADIENTSHADER_GRADIENT] = self.gradient  
                              return True  
                          
                          
                          def InitRender(self, sh, irs) :  
                              self.gradient = sh[c4d.PY_GRADIENTSHADER_GRADIENT]  
                              if (not self.gradient) or (not self.gradient.InitRender(irs)) : return c4d.INITRENDERRESULT_OUTOFMEMORY  
                              return 0  
                          
                          
                          def Output(self, sh, cd) :  
                              return self.gradient.CalcGradientPixel(cd.p.x)  
                           
                          
                          def FreeRender(self, sh) :  
                              if (self.gradient) : self.gradient.FreeRender()  
                              self.gradient = None  
                          
                          
                        def RegisterPyGradient() :  
                          
                          PLUGIN_ID = 1000010    #warning Please obtain your own plugin ID from http://www.plugincafe.com  
                          IDS_PY_GRADIENT = 10000    #string resource, must be manually defined  
                          
                          return plugins.RegisterShaderPlugin(PLUGIN_ID, plugins.GeLoadString(IDS_PY_GRADIENT), 0, PyGradient, "xpygradient", 0)  
                          
                        if __name__ == '__main__':  
                          RegisterPyGradient()  
                          
                        

                        xpygradient.h

                          
                        #ifndef _Xpygradient_H_  
                        #define _Xpygradient_H_  
                          
                        enum  
                        {  
                          PY_GRADIENTSHADER_GRADIENT            = 2000, // GRADIENT  
                        };  
                          
                        #endif  
                          
                        

                        ** xpygradient.res**

                          
                        CONTAINER Xpygradient  
                        {  
                          NAME Xpygradient;  
                          
                          INCLUDE Mpreview;  
                          INCLUDE Xbase;  
                          
                          GROUP ID_SHADERPROPERTIES  
                          {  
                              GRADIENT PY_GRADIENTSHADER_GRADIENT { }  
                          }  
                        }  
                          
                        

                        ** xpygradient.str**

                          
                        STRINGTABLE Xpygradient  
                        {  
                          Xpygradient "Python Gradient Shader";  
                          
                          PY_GRADIENTSHADER_GRADIENT                "Gradient";  
                        }  
                          
                        

                        ** c4d_symbols.h**

                          
                        enum  
                        {  
                          // string table definitions  
                          IDS_PY_GRADIENT = 10000,        // this entry is actually redundant, because C4D Python doesn't recognize it from here so far! That's why it's also defined in "py-gradient.pyp" itself.  
                          
                        // End of symbol definition  
                          _DUMMY_ELEMENT_  
                        };  
                          
                        

                        ** c4d_strings.str**

                          
                        // C4D-StringResource  
                        // Identifier    Text  
                          
                        STRINGTABLE  
                        {  
                          IDS_PY_GRADIENT        "Py-Gradient";  
                        }  
                          
                        

                        I guess, the plugin structure should be clear, but just for completeness:

                          
                            
                            
                            Py-Gradient/
                                py-gradient.pyp
                                res/
                                    c4d_symbols.h
                                    description/
                                        xpygradient.h
                                        xpygradient.res
                                    strings_us/
                                        c4d_strings.str
                                        description/
                                            xpygradient.str  
                            
                        

                        Maybe that helps to find out what's the problem for you. 🙂
                        I hope so!

                        Kind regards,
                        Tom

                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 09/06/2013 at 11:37, xxxxxxxx wrote:

                          Yes that does help Tom.

                          For some strange reason that I have yet to figure out. I couldn't create my own unique instance of the gradient gui. It just refused to work.
                          I could not replace:

                          node[c4d.SDKGRADIENTSHADER_COLOR] = self.gradient  
                          with  
                          node[c4d.MY_GRADIENT] = self.gradient
                          

                          But your small example works for me. So I will use that rebuild my plugin with unique ID's.

                          Vielen Dank,
                          -ScottA

                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            On 09/06/2013 at 13:10, xxxxxxxx wrote:

                            By the way, can anyone tell me why C4D doesn't use the string table definitions from c4d_symbols.h for Python  plugins?
                            But it wants this resource file nevertheless. But what for, then?

                            ** c4d_symbols.h**
                            _<_t_>_

                            enum
                            {
                              // string table definitions
                              IDS_PY_GRADIENT = 10000,        // this entry is actually redundant, because C4D Python doesn't recognize it from here so far! That's why it's also defined in "py-gradient.pyp" itself.

                            // End of symbol definition
                              _DUMMY_ELEMENT_
                            };

                            <_<_t_>_

                            Would be good if this get "fixed" some day. 😉

                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              On 10/06/2013 at 00:12, xxxxxxxx wrote:

                              The symbols file is is needed because it is part of the resource associated with a plugin or more
                              specifically its look up table the resource parser is using to identify certain elements.

                              In python description ids are imported properly(automatically) from the symbols file, everything 
                              else - custom ids, dialog ids is not. The reason ? Only god knows why. You have either to copy 
                              the values or write a little parser for the symbols file which does autoimport its members to your 
                              project.

                              The downside of auto importing - if you are using an IDE,  it won't know your symbols constants 
                              anymore, so will loose the autocomplete feature on these. That is why I personally went back
                              to simply copy pasting the symbols file. With a little macro you can make it one press of a button.

                              edit : You could of course write an autoimporter that doesn't work at runtime, but (over)writes
                              a python symbols definition py(c) file, but doing that properly will be a bit more work. as you
                              will have to analyze existing code in the file and so on.

                              1 Reply Last reply Reply Quote 0
                              • H
                                Helper
                                last edited by

                                On 10/06/2013 at 00:44, xxxxxxxx wrote:

                                Originally posted by xxxxxxxx

                                In python description ids are imported properly(automatically) from the symbols file, everything 
                                else - custom ids, dialog ids is not. The reason ? Only god knows why. You have either to copy 
                                the values or write a little parser for the symbols file which does autoimport its members to your 
                                project.

                                ⭐ https://github.com/NiklasRosenstein/c4dtools#example-code

                                c4dtools does this for you, and it also allows parsing the description resources so you don't have to
                                fuzz with the symbolcache. Well, if you're using an IDE, you won't have the symbols in the auto-
                                ompletion, but you could also write a script that parses the resource symbols and creates an
                                importable Python file that contains the resources.

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