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 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