SOLVED Iterate through selected Materials

Is it possible to make an iteration through a selection of Materials.
I'd like to rename the texture after the material. It works but only on all materials in the doc. how do i specify it on to a selection of materials?


import c4d
from c4d import gui
from c4d import storage
import  os
#Welcome to the world of Python


def changeTexture(shader):


    # shader ID
    texturePath = shader[c4d.BITMAPSHADER_FILENAME]
    # split aboslute path
    oldTexturename = os.path.split(texturePath)
    fileExtension = os.path.splitext(texturePath)
    # add prefix to
    newTexturename = matName + fileExtension[1]
    print (newTexturename)
    newTexturePath = os.path.join(oldTexturename[0], newTexturename)
    print (newTexturePath)

    # rename texture
    try :
        os.rename(texturePath, newTexturePath)
        print("Source path renamed to destination path successfully.")
    except OSError as error:
        print(error)

    # Assign the new value
    shader[c4d.BITMAPSHADER_FILENAME] = newTexturePath
    shader.Message(c4d.MSG_UPDATE)




# Main function
def main() :
    c4d.CallCommand(1029486) # Project Asset Inspector...
    c4d.CallCommand(1029813) # Select All
    c4d.CallCommand(1029820) # Globalize Filenames

    # Iterate over selected material

    mat = doc.GetFirstMaterial()
    while mat:
        shader = mat.GetFirstShader()

        global matName
        matName = mat.GetName()
        while shader:
        # Test if the current node is a bitmap shader.
            if shader.CheckType(c4d.Xbitmap) :
                changeTexture(shader)
            shader (shader.GetDown())
            shader = shader.GetNext()
        mat = mat.GetNext()


    # c4d.CallCommand(200000273) # Reload All Textures

# Execute main()
if __name__=='__main__':
    main()

Hello @moko,

thank you for reaching out to us. There are in principle two ways to do this. BaseDocument contains a handful of methods to retrieve the 'active', i.e., selected, entities of some type, e.g., objects, tags, and also materials. The method in question would be BaseDocument.GetActiveMaterials().

There is also a more general-purpose approach via BaseList2D.GetBit() for retrieving the selection state of a node, which will also work for node types that that do not have such special purpose methods. For details, please see the example at the end of this posting.

Cheers,
Ferdinand

"""Example for determining the selection state of BaseList2D nodes via GetBit().

To be run as a Script Manger script. Will print out the names of the selected
materials.

As discussed in:
    https://plugincafe.maxon.net/topic/13446/
"""

import c4d

def main():
    """
    """
    # We can get the active Materials with BaseDocument.GetActiveMaterials()
    for activeMaterial in doc.GetActiveMaterials():
        print (f"{activeMaterial.GetName()} is a selected Material.")

    print ("\n", "-" * 100, "\n")

    # Or we can iterate over the materials and use the bit flags of the nodes
    # to determine their selection state. The advantage here is that this will
    # work for any BaseList2D and not only the ones (objects, tags, materials,
    # etc.) where specific methods exist to retrieve the selected/active ones.
    # The relevant method is BaseList2D.GetBit() and the relevant bit mask is
    # BIT_ACTIVE - which indicates the selection state of the BaseList2D.

    # Get the first material like you did.
    material = doc.GetFirstMaterial()
    if not material:
        return

    while material:
        # Print out only materials that are selected.
        if material.GetBit(c4d.BIT_ACTIVE):
            print (f"{material.GetName()} is a selected Material.")
        material = material.GetNext()


# Execute main()
if __name__=='__main__':
    main()

@ferdinand

Thank you very much! The second way works great. I didnt get the first approach to work, but the second does well 🙂

Here is the script if someone needs it. It is probably messy I am not a programmer, but it does write the names of the selected materials into the texturname


import c4d
from c4d import gui
from c4d import storage
import  os
#Welcome to the world of Python


def changeTexture(shader):


    # shader ID
    texturePath = shader[c4d.BITMAPSHADER_FILENAME]
    # split aboslute path
    oldTexturename = os.path.split(texturePath)
    fileExtension = os.path.splitext(texturePath)
    # add prefix to
    newTexturename = matName + fileExtension[1]
    print (newTexturename)
    newTexturePath = os.path.join(oldTexturename[0], newTexturename)
    print (newTexturePath)

    # rename texture
    try :
        os.rename(texturePath, newTexturePath)
        print("Source path renamed to destination path successfully.")
    except OSError as error:
        print(error)

    # Assign the new value
    shader[c4d.BITMAPSHADER_FILENAME] = newTexturePath
    shader.Message(c4d.MSG_UPDATE)


# Main function
def main() :
    c4d.CallCommand(1029486) # Project Asset Inspector...
    c4d.CallCommand(1029816) # Select Assets of Active Elements
    c4d.CallCommand(1029820) # Globalize Filenames

    # Iterate over selected material
    material = doc.GetFirstMaterial()
    if not material:
        return

    while material:
        if material.GetBit(c4d.BIT_ACTIVE):
            shader = material.GetFirstShader()

            global matName
            matName = material.GetName()
            while shader:
            # Test if the current node is a bitmap shader.
                if shader.CheckType(c4d.Xbitmap) :
                    changeTexture(shader)
                shader (shader.GetDown())
                shader = shader.GetNext()

        material = material.GetNext()

    c4d.CallCommand(200000273) # Reload All Textures

# Execute main()
if __name__=='__main__':
    main()