Render to PictureViewer without breaking plugin

On 17/07/2015 at 09:00, xxxxxxxx wrote:

Now that I've finally figured out how to create radio buttons in a res file (why was this info not available before in the forums?) and bitmap icons, there are just a few remaining roadblocks that I have become accustomed to.  If anyone is feeling magical and want to try to answer another longstanding question that I haven't been able to figure out, here you go (Thank you in advance!) :

I have to break my plugins before Cinema will allow me to render to the picture viewer.  This hasn't been much of a problem because I need to break the plugins anyways to hand my projects over to my co-workers who are too inept to follow my repeated instructions on how to install my plugins (Anyone else have this problem?).  What code do I need to allow me to let Cinema render when I have an object plugin in the scene?  Let me know if I need to post any example code.

P.S.:  Yeah, I know that these seem to simple questions, but as it turns out, the basics are the hardest things to find answers for in programming.

-David

On 20/07/2015 at 08:30, xxxxxxxx wrote:

Hi David,

can you please elaborate a bit more? What do you mean by "break my plugins"?`
Also not sure about the "special code" to let Cinema render. I guess, you already know the Py-RoundedTube example from the Python SDK. This renders just fine.

On 21/07/2015 at 10:42, xxxxxxxx wrote:

Hi Andreas,

By "break" I meant Make Editable.  Most of my object plugins don't render unless they are Made Editable, but some do.  I'll go ahead and post an entire plugin if it helps.  It doesn't have all of it's problems worked out, but the basic functionality works fine:

import c4d, math, string, random
from c4d import gui, plugins, utils, bitmaps
import os
  
# GoldenFlower 0.9
# Author: David Cox
# 07/01/2015
  
PLUGIN_ID = 9329937
  
#GROUP_FLOWER = 1000,
PEDAL_LINK = 1001, # Pedal Link
PEDAL_COUNT = 1002, # Number of pedals
FLOWER_SPREAD = 1003, # Pedal Spread
PEDAL_OPEN_AMOUNT = 1004, # Amount of open flower
  
GROUP_BEND = 1005,
BIAS_BEND = 1006, # Bend Bias
BEND_AMOUNT = 1007, # Bend Amount
RAND_BEND_AMOUNT = 1008, # Random Bend Amount
BEND_HEIGHT = 1009, # Bend Height
RAND_BEND_HEIGHT = 1010, # Random Bend Height
RANDOM_SEED = 1011, # Random Bend Seed
  
GROUP_TRANSFORMS = 1012,
BIAS_POS = 1013, # Position Bias
POS_X = 1014, # Pos-X
RAND_POS_X = 1015, # Rand_Pos-X
POS_Y = 1016, # Pos-Y
RAND_POS_Y = 1017, # Rand_Pos-Y
POS_Z = 1018, # Pos-Z
RAND_POS_Z = 1019, # Rand_Pos-Z
  
BIAS_SCALE = 1021, # Scale Bias
SCALE_X = 1022, # Scale-X
RAND_SCALE_X = 1023, # Rand_Scale-X
SCALE_Y = 1024, # Scale-Y
RAND_SCALE_Y = 1025, # Rand_Scale-Y
SCALE_Z = 1026, # Scale-Z
RAND_SCALE_Z = 1027, # Rand_Scale-Z
  
BIAS_ROT = 1029, # Rotation Bias
ROT_X = 1030, # Rot-X
RAND_ROT_X = 1031, # Rand_Rot-X
ROT_Y = 1032, # Rot-Y
RAND_ROT_Y = 1033, # Rand_Rot-Y
ROT_Z = 1034, # Rot-Z
RAND_ROT_Z = 1035, # Rand_Rot-Z
FLOWER_RADIUS = 1036, # Flower Radius
MULTI_1 = 1037,
MULTI_2 = 1038,
MULTI_3 = 1039,
MULTIBUTTON = 1040,
RADIOBUTTONS = 1041,
ABITMAPBUTTON_A = 1042,
ABITMAPBUTTON_B = 1043,
ABITMAPBUTTON_C = 1044,
  
  
class GoldenFlower(c4d.plugins.ObjectData) :
    """GOLDEN FLOWER"""
  
    def __init__(self) :
        self.SetOptimizeCache(True)
  
  
    def Init(self, op) :
        self.InitAttr(op, float, [1002]) # Number of pedals
        self.InitAttr(op, float, [1003]) # Pedal Spread
        self.InitAttr(op, float, [1004]) # Amount of open flower
  
        self.InitAttr(op, float, [1006]) # Bend Bias
        self.InitAttr(op, float, [1007]) # Bend Amount
        self.InitAttr(op, int, [1008]) # Random Bend Amount
        self.InitAttr(op, float, [1009]) # Bend Height
        self.InitAttr(op, int, [1010]) # Random Bend Height
        self.InitAttr(op, int, [1011]) # Random Seed
  
        self.InitAttr(op, float, [1013]) # Position Bias
        self.InitAttr(op, float, [1014]) # Pos-X
        self.InitAttr(op, int, [1015]) # Rand_Pos-X
        self.InitAttr(op, float, [1016]) # Pos-Y
        self.InitAttr(op, int, [1017]) # Rand_Pos-Y
        self.InitAttr(op, float, [1018]) # Pos-Z
        self.InitAttr(op, int, [1019]) # Rand_Pos-Z
  
        self.InitAttr(op, float, [1021]) # Scale Bias
        self.InitAttr(op, float, [1022]) # Scale-X
        self.InitAttr(op, int, [1023]) # Rand_Scale-X
        self.InitAttr(op, float, [1024]) # Scale-Y
        self.InitAttr(op, int, [1025]) # Rand_Scale-Y
        self.InitAttr(op, float, [1026]) # Scale-Z
        self.InitAttr(op, int, [1027]) # Rand_Scale-Z
  
        self.InitAttr(op, float, [1029]) # Rotation Bias
        self.InitAttr(op, float, [1030]) # Rotation-X
        self.InitAttr(op, int, [1031]) # Rand_Rotation-X
        self.InitAttr(op, float, [1032]) # Rotation-Y
        self.InitAttr(op, int, [1033]) # Rand_Rotation-Y
        self.InitAttr(op, float, [1034]) # Rotation-Z
        self.InitAttr(op, int, [1035]) # Rand_Rotation-Z
        self.InitAttr(op, float, [1036]) # Flower Radius
  
  
        op[1002] = 100.0  # Number of pedals
        op[1003] = 0.8 # Pedal Spread
        op[1004] = 10 # Amount of open flower
  
        op[1006] = 0 # Bend Bias
        op[1007] = 0 # Bend Amount
        op[1008] = 0 # Random Bend Amount
        op[1009] = 0 # Bend Height
        op[1010] = 0 # Random Bend Height
        op[1011] = 1 # Random Seed
  
        op[1013] = 0 # Position Bias
        op[1014] = 0 # Pos-X
        op[1015] = 0 # Rand_Pos-X
        op[1016] = 0 # Pos-Y
        op[1017] = 0 # Rand_Pos-Y
        op[1018] = 0 # Pos-Z
        op[1019] = 0 # Rand_Pos-Z
  
        op[1021] = 0 # Scale Bias
        op[1022] = 0 # Scale-X
        op[1023] = 0 # Rand_Scale-X
        op[1024] = 0 # Scale-Y
        op[1025] = 0 # Rand_Scale-Y
        op[1026] = 0 # Scale-Z
        op[1027] = 0 # Rand_Scale-Z
  
        op[1029] = 0 # Rotation Bias
        op[1030] = 0 # Rotation-X
        op[1031] = 0 # Rand_Rotation-X
        op[1032] = 0 # Rotation-Y
        op[1033] = 0 # Rand_Rotation-Y
        op[1034] = 0 # Rotation-Z
        op[1035] = 0 # Rand_Rotation-Z
        op[1036] = 3.0 # Flower Radius
  
        return True
  
    def Message(self, node, type, data) :
        if type==c4d.MSG_DESCRIPTION_COMMAND:
            if data['id'][0].id==1042:
                self.thePedalA = True
                self.thePedalB = False
                self.thePedalC = False
            if data['id'][0].id==1043:
                self.thePedalB = True
                self.thePedalA = False
                self.thePedalC = False
            if data['id'][0].id==1044:
                self.thePedalC = True
                self.thePedalA = False
                self.thePedalB = False
            node.Message(c4d.MSG_CHANGE)
        return True
  
    def GetVirtualObjects(self, op, hierarchyhelp) :
 # ******************** Set variables *************************************
        v = c4d.Vector
        rad = c4d.utils.Rad
        doc = op.GetDocument()
        baseNull = c4d.BaseObject(c4d.Onull)
  
        pedal_MyData = op.GetDataInstance()
        pedalLink = pedal_MyData.GetObjectLink(1001)
        if pedalLink != None:
            pedalLink[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1
            pedalLink[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 1
        pedalNum = op[1002]
        pedalSpread = op[1003]
        openAmount = op[1004]/1000
  
        bendBias = op[1006]
        bendAmount = rad(op[1007])
        randBendAmount = op[1008]
        bendHeight = op[1009]*4
        randBendHeight  = op[1010]
        randSeed = random.seed(op[1011])
  
        posBias = op[1013]
        posX = op[1014]
        randPosX = op[1015]
        posY = op[1016]
        randPosY = op[1017]
        posZ = op[1018]
        randPosZ = op[1019]
  
        scaleBias = op[1021]
        scaleX = op[1022]/100
        randScaleX = op[1023]
        scaleY = op[1024]/100
        randScaleY = op[1025]
        scaleZ = op[1026]/100
        randScaleZ = op[1027]
  
        rotBias = op[1029]
        rotX = rad(op[1030])
        randRotX = op[1031]
        rotY = rad(op[1032])
        randRotY = op[1033]
        rotZ = rad(op[1034])
        randRotZ = op[1035]
        flowerRad = op[1036]
        bitmapButtonA = op[1042]
        bitmapButtonB = op[1043]
        bitmapButtonC = op[1044]
        # ******************** End Variable Assignment Area ******************
  
        bound = flowerRad
        rotVal = 0.0
        tau = 6.28318530718 # pi * 2
        phi = (1 + math.sqrt(5)) / 2 #1.618...
        #calculate the golden angle in radians
        golden_angle = tau * (2 - phi)
        theta = 0.0
        doc = c4d.documents.GetActiveDocument()
  
        pedalTest_A = doc.SearchMaterial("Pedal_A")
        pedalTest_B = doc.SearchMaterial("Pedal_B")
        pedalTest_C = doc.SearchMaterial("Pedal_C")
  
        path, fn = os.path.split(__file__)
        fn = os.path.join(path, "pedals", "Pedal_A.c4d")
        if pedalTest_A == None:
            c4d.documents.MergeDocument(doc, fn, c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS, None)
        if pedalTest_A != None:
            c4d.documents.MergeDocument(doc, fn, c4d.SCENEFILTER_OBJECTS, None)
            pedal_A = doc.GetActiveObjects(0)
            tags = pedal_A[0].GetTags()
            for p in tags:
                if p.GetTypeName() == "Texture":
                    p.SetMaterial(pedalTest_A)
        pedal_A = doc.GetActiveObjects(0)
        pedal_A = pedal_A[0]
        pedal_A.InsertUnder(baseNull)
  
        fn = os.path.join(path, "pedals", "Pedal_B.c4d")
        if pedalTest_B == None:
            c4d.documents.MergeDocument(doc, fn, c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS, None)
        if pedalTest_B != None:
            c4d.documents.MergeDocument(doc, fn, c4d.SCENEFILTER_OBJECTS, None)
            pedal_B = doc.GetActiveObjects(0)
            tags = pedal_B[0].GetTags()
            for p in tags:
                if p.GetTypeName() == "Texture":
                    p.SetMaterial(pedalTest_B)
        pedal_B = doc.GetActiveObjects(0)
        pedal_B = pedal_B[0]
        pedal_B.InsertUnder(baseNull)
  
        fn = os.path.join(path, "pedals", "Pedal_C.c4d")
        if pedalTest_C == None:
            c4d.documents.MergeDocument(doc, fn, c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS, None)
        if pedalTest_C != None:
            c4d.documents.MergeDocument(doc, fn, c4d.SCENEFILTER_OBJECTS, None)
            pedal_C = doc.GetActiveObjects(0)
            tags = pedal_C[0].GetTags()
            for p in tags:
                if p.GetTypeName() == "Texture":
                    p.SetMaterial(pedalTest_C)
        pedal_C = doc.GetActiveObjects(0)
        pedal_C = pedal_C[0]
        pedal_C.InsertUnder(baseNull)
  
        doc.SetSelection(op)
        pedal_A[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1
        pedal_A[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 1
        pedal_B[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1
        pedal_B[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 1
        pedal_C[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1
        pedal_C[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 1
  
        if self.thePedalA == True:
            thePedal = pedal_A
        if self.thePedalB == True:
            thePedal = pedal_B
        if self.thePedalC == True:
            thePedal = pedal_C
        for n in range(int(pedalNum)) :
  
            if pedalLink == None:
                pedalClone = thePedal.GetClone()
                pedalClone = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[pedalClone], bc=c4d.BaseContainer(), mode=c4d.MODELINGCOMMANDMODE_ALL, doc = doc, flags = 0)
                pedalClone = pedalClone[0]
                pedalBound = pedalClone.GetRad() # Get the bounding box
                pedalBound += pedalBound
  
                radius = (bound * pow(n/pedalNum, pedalSpread)) * 10
                theta += golden_angle
                pos = self.polar_to_cartesian(theta, radius) #Call def
                self.makeThing(n, pos, radius, rotVal, baseNull, pedalNum, pedalClone, pedalBound, bendAmount, bendHeight, randBendAmount, randBendHeight, bendBias, posBias, scaleBias, rotBias, randPosX, randPosY, randPosZ, randScaleX, randScaleY, randScaleZ, randRotX, randRotY, randRotZ, posX, posY, posZ, scaleX, scaleY, scaleZ, rotX, rotY, rotZ)
                rotVal += openAmount
                if n > 0:
                    pedalClone[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 2
                    pedalClone[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 2
  
            if pedalLink != None:
                pedalType = pedalLink.GetTypeName()
            if pedalLink != None and pedalType != "Legacy XRef":
                pedalClone = pedalLink.GetClone()
                pedalClone = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[pedalClone], bc=c4d.BaseContainer(), mode=c4d.MODELINGCOMMANDMODE_ALL, doc = doc, flags = 0)
                pedalClone = pedalClone[0]
                pedalBound = pedalClone.GetRad() # Get the bounding box
                pedalBound += pedalBound
  
                radius = (bound * pow(n/pedalNum, pedalSpread)) * 10
                theta += golden_angle
                pos = self.polar_to_cartesian(theta, radius) #Call def
                self.makeThing(n, pos, radius, rotVal, baseNull, pedalNum, pedalClone, pedalBound, bendAmount, bendHeight, randBendAmount, randBendHeight, bendBias, posBias, scaleBias, rotBias, randPosX, randPosY, randPosZ, randScaleX, randScaleY, randScaleZ, randRotX, randRotY, randRotZ, posX, posY, posZ, scaleX, scaleY, scaleZ, rotX, rotY, rotZ)
                rotVal += openAmount
                if n > 0:
                    pedalClone[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 2
                    pedalClone[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 2
  
        c4d.EventAdd()
        return baseNull
  
    def makeThing(self, n, pos, radius, rotVal, baseNull, pedalNum, pedalClone, pedalBound, bendAmount, bendHeight, randBendAmount, randBendHeight, bendBias, posBias, scaleBias, rotBias, randPosX, randPosY, randPosZ, randScaleX, randScaleY, randScaleZ, randRotX, randRotY, randRotZ, posX, posY, posZ, scaleX, scaleY, scaleZ, rotX, rotY, rotZ) :
        rad = c4d.utils.Rad
        theThing = pedalClone
        theThing.SetRelPos(pos)
        theScale = pow(radius,0.5)*0.265
        pos = -pos
        N = pos.GetNormalized()
        upVec = c4d.Vector(0,1,0)
        dist = pos.GetLength()
        nn = c4d.utils.VectorToHPB(N)
        norm = c4d.Vector(0,0,0)
        if N != None:
            norm = nn.Cross(upVec).GetNormalized()
        #norm = c4d.Vector(nn.x + rotVal, N.y + rotVal*0.3, nn.z)
        norm = c4d.Vector(nn.x, N.y + rotVal*0.3, nn.z)
        theThing.SetRelRot(norm)
        rot = theThing.GetRelRot()
        scale = theThing.GetRelScale()
        pos = theThing.GetRelPos()
  
        rand = float(random.randrange(-100, 100))/100
  
        randBendAmount *= rand
        randBendAmount = randBendAmount/100
        randBendHeight *= rand
  
        randPosX *= rand
        randPosY *= rand
        randPosZ *= rand
        randScaleX *= rand
        randScaleX = randScaleX/100
        randScaleY *= rand
        randScaleY = randScaleY/100
        randScaleZ *= rand
        randScaleZ = randScaleZ/100
        randRotX *= rand
        randRotX = randRotX/100
        randRotY *= rand
        randRotY = randRotY/100
        randRotZ *= rand
        randRotZ = randRotZ/100
  
        theThing.SetRelPos(c4d.Vector(posX+pos.x+randPosX, posY+pos.y+randPosY, posZ+pos.z+randPosZ))
        theThing.SetRelScale(c4d.Vector(scaleX+scale.x+randScaleX, scaleY+scale.y+randScaleY, scaleZ+scale.z+randScaleZ))
        theThing.SetRelRot(c4d.Vector(rotX+rot.x+randRotX, rotY+rot.y+randRotY, rotZ+rot.z+randRotZ))
  
        pedalBend = c4d.BaseObject(c4d.Obend)
        pedalBend.InsertUnder(theThing)
        pedalBend[c4d.DEFORMOBJECT_SIZE] = pedalBound
        pedalBend[c4d.DEFORMOBJECT_STRENGTH] = bendAmount+randBendAmount
        pedalBend[c4d.BENDOBJECT_KEEPYAXIS] = True
        pedalBend[c4d.DEFORMOBJECT_ANGLE] = rad(-90)
        pedalBend[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1
        #print "n: ",n
        #print "pedalNum: ", pedalNum
        pedalBend[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = pedalBound.y/2 + bendHeight+randBendHeight
        
        #pedalBend[c4d.DEFORMOBJECT_STRENGTH] = (bendAmount+randBendAmount) + 10*(pow(bendBias, n/pedalNum))
  
        theThing.InsertUnder(baseNull)
  
  
    def polar_to_cartesian(self, theta, radius) :
        sn, cs = c4d.utils.SinCos(theta)
        return c4d.Vector(cs*radius, 0, sn*radius)
  
  
    def SetGlobalPosition(self, obj, pos) :
        m = obj.GetMg()
        m.off = pos
        obj.SetMg(m)
  
    def SetGlobalRotation(self, obj, rot) :
        m = obj.GetMg()
        pos = m.off
        scale = c4d.Vector( m.v1.GetLength(),
                            m.v2.GetLength(),
                            m.v3.GetLength())
        m = utils.HPBToMatrix(rot)
        m.off = pos
        m.v1 = m.v1.GetNormalized() * scale.x
        m.v2 = m.v2.GetNormalized() * scale.y
        m.v3 = m.v3.GetNormalized() * scale.z
        obj.SetMg(m)
  
BITMAP_ID1 = 103721
BITMAP_ID2 = 103722
BITMAP_ID3 = 103723
if __name__ == '__main__':
    #main()
    bmp = c4d.bitmaps.BaseBitmap()
    dir, file = os.path.split(__file__)
    path, fn = os.path.split(__file__)
    fn = os.path.join(dir, "res", "Icon.tif")
    bmp.InitWith(fn)
    buttonimageA = bitmaps.BaseBitmap()                         #We need an instance of BaseBitmap class to use an image 
    buttonimageA.InitWith(os.path.join(path, "res", "pedal_A.tif"))#The location where the button image exists
    buttonimageB = bitmaps.BaseBitmap()                         #We need an instance of BaseBitmap class to use an image 
    buttonimageB.InitWith(os.path.join(path, "res", "pedal_B.tif"))#The location where the button image exists
    buttonimageC = bitmaps.BaseBitmap()                         #We need an instance of BaseBitmap class to use an image 
    buttonimageC.InitWith(os.path.join(path, "res", "pedal_C.tif"))#The location where the button image exists
    gui.RegisterIcon(BITMAP_ID1, buttonimageA)                  #We need to register custom images & icons
    gui.RegisterIcon(BITMAP_ID2, buttonimageB)                  #We need to register custom images & icons
    gui.RegisterIcon(BITMAP_ID3, buttonimageC)                  #We need to register custom images & icons
    result = plugins.RegisterObjectPlugin(
        id=PLUGIN_ID,
        str="GoldenFlower",
        g=GoldenFlower,
        description="Ogolden_flower",
        info=c4d.OBJECT_GENERATOR,
        icon=bmp
    )

On 22/07/2015 at 03:49, xxxxxxxx wrote:

Hi,

I'm sorry, we are not supposed to debug code. And it would be a good idea to give at least an overview, what your code is supposed to do.
I briefly looked over your code and I think you have several problems in there.

Most important:
You are not allowed to modify the active scene with GetVirtualObjects(). Please have look at documentation on ObjectData, GetVirtualObjects() and important threading information.
I noticed for example MergeDocument().

Objects can only be inserted once into a scene, while you try to get the active object and insert it under your generated object. That won't work for several reasons:
- The active object is already in the scene and you can't remove it, because you are not allowed to in GVO. Instead you should have a look at the OBJECT_INPUT flag on RegisterObjectPlugin().
- Getting the active object makes no sense during rendering. The scene gets copied for rendering and there simply won't be any active object in there.

You are loading several scene files with MergeDocument(), which (as mentioned before) already is a bad idea, but think of situations like for example TeamRender. How is TeamRender supposed to find these files on a different machine?

I think, you will have to rework and restructure your plugin to properly work in all situations, especially for rendering. Sorry, to say this.