Undo loading and replacing materials



  • On 16/06/2017 at 03:05, xxxxxxxx wrote:

    import c4d
      
    def main() :
      
        File=r"d:	est\Mats.c4d"
      
        TempDoc = c4d.documents.LoadDocument(File, c4d.SCENEFILTER_MATERIALS)
        MatListTemp = list()
        MatTemp = TempDoc.GetFirstMaterial()
        while(MatTemp) :
            nMatTemp = MatTemp.GetNext()
            MatListTemp.append(MatTemp)
            MatTemp = nMatTemp
        TempDoc.Remove()
      
        MatCurentDoc = doc.GetFirstMaterial()
        MatList = list()
        while(MatCurentDoc) :
            nMatCurentDoc = MatCurentDoc.GetNext()
            MatList.append(MatCurentDoc)
            MatCurentDoc = nMatCurentDoc
      
      
        doc.StartUndo()
      
        for Mat in MatList:
            for MatTemp in MatListTemp:
                if MatTemp.GetName() == Mat.GetName() :
                    LayerMat = Mat.GetLayerObject(doc)
                    ObjLink = Mat[c4d.ID_MATERIALASSIGNMENTS]
      
                    list_tags = list()
                    for i in xrange(ObjLink.GetObjectCount()) :
                        list_tags.append(ObjLink.ObjectFromIndex(doc, i))
      
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, Mat)
      
                    Mat.Remove()
                    doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat)
      
                    doc.InsertMaterial(MatTemp)
                    doc.AddUndo(c4d.UNDOTYPE_NEW, MatTemp)
      
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, MatTemp)
                    MatTemp.SetLayerObject(LayerMat)
      
                    for tag in list_tags:
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, tag)
                        tag[c4d.TEXTURETAG_MATERIAL] = MatTemp
      
        doc.EndUndo()
        c4d.EventAdd()
      
    if __name__ == '__main__':
        main()
    

    I'm downloading and replacing the materials with a script. All assigned objects are visible in the material assignments. If you undo the action (Ctrl + Z), the objects are missing in the material assignments.



  • On 16/06/2017 at 04:03, xxxxxxxx wrote:

    Yo do undo in the wrong under. Take the Add Undo command as Save Current State.

    So logically

                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, Mat)
      
                    doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat)
                    Mat.Remove()
      
                    doc.AddUndo(c4d.UNDOTYPE_NEW, MatTemp) #Since MatTemp already exist in memory
                    doc.InsertMaterial(MatTemp)
      
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, MatTemp)
                    MatTemp.SetLayerObject(LayerMat)
      
                    for tag in list_tags:
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, tag)
                        tag[c4d.TEXTURETAG_MATERIAL] = MatTemp
    


  • On 16/06/2017 at 04:34, xxxxxxxx wrote:

    Actually, UNDOTYPE_NEW needs to be called after  the insertion. :)

    https://developers.maxon.net/docs/Cinema4DPythonSDK/html/modules/c4d.documents/BaseDocument/index.html?highlight=addundo#BaseDocument.AddUndo

    Cheers



  • On 16/06/2017 at 04:41, xxxxxxxx wrote:

    UNDOTYPE_NEW New object/node/tag etc. was created. (Needs to be called AFTER action.)

    _<_t_>_

    The result is similar, after undo(ctrl+z) in "Material editor: Assignment" empty.



  • On 16/06/2017 at 04:52, xxxxxxxx wrote:

    If you save and reopen the project, then everything will be fine



  • On 19/06/2017 at 08:38, xxxxxxxx wrote:

    Hi,

    I think both Niklas and gr4phos are basically right, it has to do with the order of AddUndo() and action.
    Just to avoid confusion, in the original script posted doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat) was wrongly called after Remove(), UNDOTYPE_DELETE has to be done before the action (correctly pointed out by gr4ph0s). Then gr4ph0s probably got confused himself and mixed up the order of  UNDOTYPE_NEW in his script, which has to be done after the action (as correctly pointed out by Niklas).
    Getting both of these right, should fix the issue.



  • On 19/06/2017 at 21:28, xxxxxxxx wrote:

    Alas it does not work

    screencast



  • On 20/06/2017 at 02:57, xxxxxxxx wrote:

    Hi,

    please forgive me for not taking a closer look first. The AddUndo() order seemed like an obvious bug and explained the issues pretty well.
    The actual issue is, that you are removing the old material too early from the document. So when the material assignment gets changed and the undo step is added, the document already has no more reference to the old material.

    Here's the fixed script, with a few other notes:

    import c4d
      
    def main() :
      
        File = "<some path>/Mats.c4d"
      
        TempDoc = c4d.documents.LoadDocument(File, c4d.SCENEFILTER_MATERIALS)
        MatListTemp = list()
        MatTemp = TempDoc.GetFirstMaterial()
        while(MatTemp) :
            MatListTemp.append(MatTemp.GetClone()) # use clone here, later on you don't want to insert a material already inserted in another doc
            MatTemp = MatTemp.GetNext()
        TempDoc.Remove()
      
        MatCurentDoc = doc.GetFirstMaterial()
        MatList = list()
        while(MatCurentDoc) :
            MatList.append(MatCurentDoc)
            MatCurentDoc = MatCurentDoc.GetNext()
      
        doc.StartUndo()
      
        for Mat in MatList:
            for MatTemp in MatListTemp:
                if MatTemp.GetName() == Mat.GetName() :
                    LayerMat = Mat.GetLayerObject(doc)
                    ObjLink = Mat[c4d.ID_MATERIALASSIGNMENTS]
      
                    list_tags = list()
                    for i in xrange(ObjLink.GetObjectCount()) :
                        print ObjLink.ObjectFromIndex(doc, i)
                        list_tags.append(ObjLink.ObjectFromIndex(doc, i))
      
                    #doc.AddUndo(c4d.UNDOTYPE_CHANGE, Mat) # redundant
      
                    # moved to the end
                    #Mat.Remove()
                    #doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat)
      
                    doc.InsertMaterial(MatTemp)
                    doc.AddUndo(c4d.UNDOTYPE_NEW, MatTemp)
      
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, MatTemp)
                    MatTemp.SetLayerObject(LayerMat)
      
                    for tag in list_tags:
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, tag)
                        tag[c4d.TEXTURETAG_MATERIAL] = MatTemp
      
                    doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat)  # swapped, AddUndo(DELETE) before Remove()
                    Mat.Remove()
                    #doc.AddUndo(c4d.UNDOTYPE_DELETE, Mat)
      
        doc.EndUndo()
        c4d.EventAdd()
      
    if __name__ == '__main__':
        main()
    


  • On 20/06/2017 at 03:19, xxxxxxxx wrote:

    thank you, things work. 👍


Log in to reply