Navigation

    • Register
    • Login
        No matches found
    • Search
    1. Home
    2. JohnTerenece
    J

    JohnTerenece

    @JohnTerenece

    2
    Reputation
    31
    Posts
    23
    Profile views
    0
    Followers
    0
    Following
    Joined Last Online

    • Profile
    • More
      • Following
      • Followers
      • Topics
      • Posts
      • Best
      • Groups
    JohnTerenece Follow

    Best posts made by JohnTerenece

    RE: DESC_PARENT_COLLAPSE Display

    Thanks for the response.

    DESC_GUIOPEN works having the twirl down open by default. What I'm looking for is the ability to modify whether or not it is actively open based on controls by the user. For example if "Angle Threshold" is greater than 90 degrees than have it twirled down, otherwise have it closed.

    John Terenece

    posted in Cinema 4D SDK •
    BaseTake AddTake

    Hi.

    I am currently working on an object plugin that would utilize Takes for a user to be able to quickly iterate through different potential versions of their scene. I've looked through the sdk and the different manuals that are available and I believe I understand the processes required.

    My issue comes in with the amount of time it take Cinema to run my plugin in regards to the creation of the Takes and if this is just the time that it takes to create them.

    I created a simple scene with a hundred objects underneath my plugin. With the code below I create a Take and assign a layer to each of the child objects. For time testing I create an additional 500 Takes using the first Take as the cloneFrom inside AddTake. This isn't a final version of my code just a test example.

    The code is executed on a button press.

    
    			case idRunTakes:
    			{
    				TakeData* takeData = doc->GetTakeData();
    				if (!takeData)
    					return TRUE;
    
    				LayerObject *hideLayer = LayerObject::Alloc();
    
    				const Vector hsv = Vector(1.0, 0, 0);
    				const Vector rgb = HSVToRGB(hsv);
    				newTakeTime = 0;
    				settingTakeTime = 0;
    				LayerData newdata;
    				newdata.color = rgb;
    				newdata.solo = FALSE;
    				newdata.view = FALSE;
    				newdata.render = FALSE;
    				newdata.manager = TRUE;
    				newdata.locked = FALSE;
    				newdata.generators = FALSE;
    				newdata.deformers = FALSE;
    				newdata.expressions = FALSE;
    				newdata.animation = FALSE;
    				newdata.xref = TRUE;
    				hideLayer->SetLayerData(doc, newdata);
    				hideLayer->SetName("Hide Layer"_s);
    
    				GeListHead* layerList = NULL;
    				layerList = doc->GetLayerObjectRoot();
    
    				layerList->InsertLast(hideLayer);
    				maxon::BaseArray<BaseObject*> childObjArray;
    				GatherAllChildObjects(splineObj->GetDown(), childObjArray);
    
    				DescID aliasLinkDId = DescLevel(ID_LAYER_LINK, DA_ALIASLINK, 0);
    				GeData setData;
    				setData.SetBaseList2D((BaseList2D*)hideLayer);
    
    				Float createNewTakesTime = 0;
    				Float timeStart = 0;
    				Float loopTimeStart = GeGetMilliSeconds();
    
    				timeStart = GeGetMilliSeconds(); 
    				BaseTake* newTake = takeData->AddTake(String("Take " + String::IntToString(0)), nullptr, nullptr);
    				if (newTake == nullptr)
    					return TRUE;
    
    				createNewTakesTime = createNewTakesTime + GeGetMilliSeconds() - timeStart;
    				for (Int32 childObjIndex = 0; childObjIndex < childObjArray.GetCount(); childObjIndex++)
    				{
    					BaseOverride* overrideNode = newTake->FindOrAddOverrideParam(takeData, childObjArray[childObjIndex], aliasLinkDId, setData);
    					if (overrideNode == nullptr)
    						return TRUE;
    
    					childObjArray[childObjIndex]->SetLayerObject(hideLayer);
    					overrideNode->UpdateSceneNode(takeData, aliasLinkDId);
    				}
    
    
    				for (Int32 takeIndex = 1; takeIndex < 501; takeIndex++)
    				{
    					timeStart = GeGetMilliSeconds();
    // This is the line taking up a lot of time
    					BaseTake* loopTake = takeData->AddTake(String("Take " + String::IntToString(takeIndex)), nullptr, newTake);
    					if (loopTake == nullptr)
    						return TRUE;
    					createNewTakesTime = createNewTakesTime + GeGetMilliSeconds() - timeStart;
    					
    				}
    				ApplicationOutput("Take time " + String::FloatToString(createNewTakesTime) + "    " + String::FloatToString(GeGetMilliSeconds() - loopTimeStart - createNewTakesTime));
    				break;
    			}
    
    
    // Code for getting all of the child objects
    void TakeCreatorPlugin::GatherAllChildObjects(BaseObject *childObject, maxon::BaseArray<BaseObject*> &objChildOfNullsArray)
    {
    	if (childObject == nullptr)
    		return;
    
    	while (childObject)
    	{
    		objChildOfNullsArray.Append(childObject);
    
    
    		GatherAllChildObjects(childObject->GetDown(), objChildOfNullsArray);
    		childObject = childObject->GetNext();
    	}
    }
    

    Running the code in my test scene gives the following print out "Take time 1920.243 20.232". So most of the time my plugin is running is taken up by adding the takes into the document. Is this just the time that Cinema takes in this kind of circumstance to create the Takes or am I just missing a crucial step,

    I've looked through the manuals in the sdk and tried to follow them.

    I've also tried to create all of the Takes empty and add the Overrides to each one individually which increases the time that step takes which isn't desirable either.

    Any help would be greatly appreciated.

    JohnTerenece

    posted in Cinema 4D SDK •

    Latest posts made by JohnTerenece

    RE: Limit On the Number Of Takes

    @m_magalhaes

    Thanks for the response.

    Might be able to use your idea as potential solution.

    John Terenece

    posted in Cinema 4D SDK •
    RE: Limit On the Number Of Takes

    Just to clarify, I know that adding more objects and such to a document in Cinema will make it use up more memory and cause it to lag when it gets bad enough. My issue is that Cinema is running fine with a certain number of takes and then I add one more and it immediately crashes.

    posted in Cinema 4D SDK •
    Limit On the Number Of Takes

    Hi.

    I am running into an issue when creating a large number of takes where Cinema is crashing on me, and this problem seems unrelated to the actual creation of the takes.

    Using my code I try to create a large number of takes, around 1400, with parameters overridden for objects in the scene, at some point during the creation process Cinema will crash. I recreated the case inside of CInema without my code by creating a take with one overridden object and then copy and pasting it, when I get to around 1400 takes in the document Cinema crashes on me.

    Is this just a limitation of Cinema when it comes to takes and that it can't handle that many inside of one document? Having multiple documents with a thousand takes in them open at the same time does not cause Cinema to crash.

    Any help would be greatly appreciated.

    John Terenece

    posted in Cinema 4D SDK •
    RE: GeDialog Update

    So I was right I was missing something incredibly simple. Thanks for the response Manuel, it works perfectly now.

    posted in Cinema 4D SDK •
    GeDialog Update

    Hello.

    I'm currently working on an Object plugin that will make changes to the objects that are its children. As part of this I want to have the user be able to open a GeDialog via a button press, the GeDialog will display controls corresponding to the child objects of my plugin.

    In my code I am successfully opening the GeDialog and gathering the child objects by sending messages to the GeDialog. On first opening the GeDialog I am creating a series of strings corresponding to the names of the child objects. All of this is working properly.

    My problem comes in when I want to try and update the GeDialog because new child objects were added. I am checking to see if the count of child objects or the order has been changed inside of a function called from GetVirtualObjects. If the hierarchy has changed I send the same messages to the GeDialog that I do when its first opened. This isn't exactly how it would be done in the final version of the plugin,

    Whenever the hierarchy is changed the messages are properly being sent but the GeDialog is not updating its layout. If I press the same button that I use to launch the GeDialog then the layout updates to what it should display.

    Here is all of the code for my stripped down plugin.

    #include "c4d_general.h"
    #include "c4d.h"
    #include "c4d_symbols.h"
    #include "main.h"
    
    #define ID_RUNDIALOG 1059364
    enum Controls
    {
    	idSendMessageLinkObject = 1000,
    	idLinkedObject,
    	idGatherChildren,
    
    	idOverallScrollGroup = 2000,
    	idGroupToFlush,
    	idControls,
    
    	idLaunchDialogWindow= 1500,
    	idBasicControlGroup,
    };
    
    maxon::Result<void> resultVoid;
    maxon::Result<BaseObject*> resultBaseObject;
    
    class ObjDialog : public GeDialog
    {
    public:
    	ObjDialog() {}
    	virtual ~ObjDialog() {}
    	virtual Bool CreateLayout();
    	virtual Bool InitValues();
    	virtual void DestroyWindow();
    	virtual Bool Command(Int32 id, const BaseContainer& msg);
    	virtual Int32 Message(const BaseContainer& msg, BaseContainer& result);
    	virtual void CreateWeighLayout(maxon::BaseArray<BaseObject*> &objForDisplay);
    	BaseObject *linkedObj;
    
    	
    
    };
    
    // Flushes and recreates the layout
    void ObjDialog::CreateWeighLayout(maxon::BaseArray<BaseObject*> &objForDisplay)
    {
    	LayoutFlushGroup(idGroupToFlush);
    	GroupBegin(idControls, BFH_SCALEFIT | BFV_SCALEFIT, 1, 0, String(), 0);
    	{
    		Int32 idContinueFrom = 10000;
    		for (Int32 objIndex = 0; objIndex < objForDisplay.GetCount(); objIndex++)
    			AddStaticText(idContinueFrom + objIndex, BFH_LEFT, 0, 0, objForDisplay[objIndex]->GetName(), 0);
    	}
    	GroupEnd();
    	LayoutChanged(idGroupToFlush);
    }
    
    Bool ObjDialog::CreateLayout()
    {
    	Bool res = GeDialog::CreateLayout();
    
    	SetTitle("Child Objects"_s);
    
    	ScrollGroupBegin(idOverallScrollGroup, BFH_SCALEFIT | BFV_SCALEFIT, SCROLLGROUP_VERT | SCROLLGROUP_HORIZ);
    	{
    		GroupBegin(idGroupToFlush, BFH_SCALEFIT | BFV_SCALEFIT, 1, 0, String(), 0);
    		{
    			GroupBegin(idControls, BFH_SCALEFIT | BFV_SCALEFIT, 5, 0, String(), 0);
    			{
    			}
    			GroupEnd();
    		}
    		GroupEnd();
    	}
    	GroupEnd();
    	
    	return res;
    }
    
    Bool ObjDialog::InitValues()
    {
    	if (!GeDialog::InitValues())
    		return false;
    	linkedObj = nullptr;
    	return true;
    }
    
    void ObjDialog::DestroyWindow() {}
    
    Bool ObjDialog::Command(Int32 id, const BaseContainer& msg)
    {
    	return true;
    }
    
    
    Int32 ObjDialog::Message(const BaseContainer& msg, BaseContainer& result)
    {
    	BaseDocument *doc = GetActiveDocument();
    	switch (msg.GetId())
    	{
    		// Links the plugin object
    		case idSendMessageLinkObject:
    		{
    			if (doc)
    			{
    				if (msg.GetLink(idLinkedObject, doc))
    					linkedObj = (BaseObject*)msg.GetLink(idLinkedObject, doc);
    			}
    			break;
    		}
    		// Gathers the children and calls the function to redo the layout
    		case idGatherChildren:
    		{
    			if (doc)
    			{
    				if (linkedObj)
    				{
    					maxon::BaseArray<BaseObject*> objForDisplay;
    					BaseObject *categoryObj = linkedObj->GetDown();
    					while (categoryObj)
    					{
    						resultBaseObject = objForDisplay.Append(categoryObj);
    						categoryObj = categoryObj->GetNext();
    					}
    					CreateWeighLayout(objForDisplay);
    				}
    
    			}
    			break;
    		}
    	}
    	return GeDialog::Message(msg, result);
    }
    
    
    class RunDialog : public ObjectData
    {
    public:
    	virtual Bool Init(GeListNode* node);
    
    	virtual BaseObject* GetVirtualObjects(BaseObject* op, HierarchyHelp* hh);
    	virtual Bool Message(GeListNode* node, Int32 type, void* t_data);
    	virtual Bool HierarchyChange(BaseObject *op, BaseDocument *doc);
    	virtual Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags);
    
    	ObjDialog dlg;
    	
    	static NodeData* Alloc() { return NewObjClear(RunDialog); }
    
    	maxon::BaseArray<BaseObject*> objArrayToCheckForMatch;
    	
    };
    
    
    Bool RunDialog::GetDDescription(GeListNode *node, Description *description, DESCFLAGS_DESC &flags)
    {
    	BaseContainer *dataInstance;   
    	const DescID *singleid;    
    	if (!description->LoadDescription(node->GetType()))
    	{
    	}
    
    	dataInstance = ((BaseList2D*)node)->GetDataInstance(); // Get the container for the tag
    	if (!dataInstance)
    		return FALSE;
    	singleid = description->GetSingleDescID();
    	DescID cid;
    
    
    	DescID DescHelperControlGroup = DescLevel(idBasicControlGroup, DTYPE_GROUP, 0);
    	if (!singleid || DescHelperControlGroup.IsPartOf(*singleid, NULL))
    	{
    		BaseContainer bc;
    		bc = GetCustomDataTypeDefault(DTYPE_GROUP);
    		bc.SetString(DESC_NAME, "Run Dialog"_s);
    		bc.SetInt32(DESC_COLUMNS, 1);
    		bc.SetInt32(DESC_DEFAULT, 1);
    		bc.SetBool(DESC_SCALEH, TRUE);
    
    		if (!description->SetParameter(DescHelperControlGroup, bc, DescLevel(ID_RUNDIALOG)))
    			return TRUE;
    	}
    
    
    	cid = DescLevel(idLaunchDialogWindow, DTYPE_BUTTON, 0);
    	if (!singleid || cid.IsPartOf(*singleid, NULL))  //  important to check for speedup c4d!
    	{
    		BaseContainer bc;
    		bc = GetCustomDataTypeDefault(DTYPE_BUTTON);
    		bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_BUTTON);
    		bc.SetString(DESC_NAME, "Open Dialog"_s);
    		if (!description->SetParameter(cid, bc, DescHelperControlGroup))
    			return TRUE;
    	}
    
    
    
    
    	flags |= DESCFLAGS_DESC::LOADED;
    
    	return TRUE;
    }
    
    Bool RunDialog::Init(GeListNode* node)
    {
    	BaseObject*		 op = (BaseObject*)node;
    	BaseContainer* data = op->GetDataInstance();
    	return true;
    }
    
    
    Bool RunDialog::Message(GeListNode* node, Int32 type, void* t_data)
    {
    	BaseContainer* dataInstance;
    	BaseObject *op = (BaseObject*)node;
    	if (!op)
    		return TRUE;
    	dataInstance = op->GetDataInstance();
    	if (!dataInstance)
    		return TRUE;
    
    	
    	if (type == MSG_DESCRIPTION_COMMAND)
    	{
    		DescriptionCommand *dc = (DescriptionCommand*)t_data;
    		if (!dc)
    			return TRUE;
    		Int32 ID = Int32(dc->_descId[0].id);
    		BaseDocument* doc = node->GetDocument();
    		if (!doc)
    			return TRUE;
    
    
    		switch (ID)
    		{
    			case idLaunchDialogWindow:
    			{
    				if (dlg.IsOpen() == false)
    					dlg.Open(DLG_TYPE::ASYNC, ID_RUNDIALOG, -1, -1, 300, 200, 0);
    				
    
    				// Message just links the plugin to the GeDialog so that I can get access to its children inside of the GeDialog
    				BaseContainer result;
    				BaseContainer msgLink;
    				msgLink.SetLink(idLinkedObject, op);
    				msgLink.SetId(idSendMessageLinkObject);
    				dlg.Message(msgLink, result);
    
    				// Message that runs the code to gather the children and recreate the layout of the GeDialog
    				BaseContainer msgGather;
    				msgGather.SetId(idGatherChildren);
    				dlg.Message(msgGather, result);
    
    
    				break;
    			}
    		}
    	}
    	
    	return true;
    }
    
    // Gets the direct children under the plugin and checks if they have been rearranged
    Bool RunDialog::HierarchyChange(BaseObject *op, BaseDocument *doc)
    {
    	if (doc == nullptr || op == nullptr)
    		return FALSE;
    
    	BaseObject *childObj = op->GetDown();
    
    	maxon::BaseArray<BaseObject*> rktNullArray;
    	while (childObj)
    	{
    		resultBaseObject = rktNullArray.Append(childObj);
    		childObj = childObj->GetNext();
    	}
    
    	Bool setDirty = FALSE;
    	if (Int32(objArrayToCheckForMatch.GetCount()) != Int32(rktNullArray.GetCount()))
    	{
    		setDirty = TRUE;
    	}
    	else
    	{
    		for (Int32 categoryIndex = 0; categoryIndex < Int32(objArrayToCheckForMatch.GetCount()); categoryIndex++)
    		{
    			if (objArrayToCheckForMatch[categoryIndex] != rktNullArray[categoryIndex])
    			{
    				setDirty = TRUE;
    				break;
    			}
    		}
    	}
    	objArrayToCheckForMatch.Reset();
    	resultVoid = objArrayToCheckForMatch.CopyFrom(rktNullArray);
    	
    	return setDirty;
    }
    
    BaseObject* RunDialog::GetVirtualObjects(BaseObject* op, HierarchyHelp* hh)
    {
    	BaseObject *nullReturn = BaseObject::Alloc(Onull);
    	BaseDocument *doc = op->GetDocument();
    	Bool setDirty = HierarchyChange(op, doc);
    
    	// Runs if the hierarchy has changed
    	if (setDirty == TRUE)
    	{
    		if (dlg.IsOpen() == TRUE)
    		{
    			BaseContainer result;
    			BaseContainer msgLink;
    			msgLink.SetLink(idLinkedObject, op);
    			msgLink.SetId(idSendMessageLinkObject);
    			dlg.Message(msgLink, result);
    
    			BaseContainer msgGather;
    			msgGather.SetId(idGatherChildren);
    			dlg.Message(msgGather, result);
    
    		}
    	}
    	return nullReturn;
    }
    
    Bool RegisterRunDialog()
    {
    	return RegisterObjectPlugin(ID_RUNDIALOG, "Run Dialog"_s, OBJECT_GENERATOR | OBJECT_INPUT, RunDialog::Alloc, "ORunDialog"_s, AutoBitmap("atom.tif"_s), 0);
    }
    
    

    In the sdk I saw that the examples that involve GeDialogs seem to all be Command plugins. Do you need to be a Command plugin to properly update in the way that I am attempting to?

    As I said above hitting the button in my plugin causes the GeDialog to update, what I am looking to have it do is update as more objects are inserted under the plugin without further user input.

    Any help would be greatly appreciated, I'm probably missing something incredibly simple.

    John Terenece

    posted in Cinema 4D SDK •
    RE: BaseTake AddTake

    Thanks for the response Ferdinand, I thought that that would be the case.

    John Terenece

    posted in Cinema 4D SDK •
    RE: BaseTake AddTake

    As an additional question when it comes to deleting the takes it seems to take a considerable amount of time to run DeleteTake on the above mentioned five hundred takes. The objects in the scene only have one overridden parameter each but it took over two minutes to run the code below to delete all of the takes using the code below running on a button press.

    Float takeDeleteTimeStart = GeGetMilliSeconds();
    				TakeData* takeData = doc->GetTakeData();
    				if (!takeData)
    					return TRUE;
    
    				BaseTake* currentTake = takeData->GetCurrentTake();
    				if (currentTake == nullptr)
    					return TRUE;
    				BaseTake *removeTakes = takeData->GetMainTake();
    				if (removeTakes)
    				{
    					BaseOverride *removeOverride;
    					BaseTake *deleteTake = removeTakes->GetDown();
    					maxon::BaseArray<BaseTake*> arrayOfTakes;
    					while (deleteTake)
    					{
    
    						arrayOfTakes.Append(deleteTake);
    						deleteTake = deleteTake->GetNext();
    					}
    
    					DescID replaceId = DescLevel(ID_BASEOBJECT_XRAY, DTYPE_BOOL, 0);
    					
    					for (Int32 deleteIndex = 0; deleteIndex < arrayOfTakes.GetCount(); deleteIndex++)
    					{
    						takeData->DeleteTake(arrayOfTakes[deleteIndex]);
    					}
    					arrayOfTakes.Flush();
    
    				}
    				ApplicationOutput("Total time to dumb delete " + String::FloatToString(GeGetMilliSeconds() - takeDeleteTimeStart));
    

    Not asking for someone to debug the code, just wondering if it taking so long to both create the Takes and delete them given the scene would be expected or if I'm missing something fundamental when it comes to Takes.

    Any help would be greatly appreciated.

    John Terenece

    posted in Cinema 4D SDK •
    BaseTake AddTake

    Hi.

    I am currently working on an object plugin that would utilize Takes for a user to be able to quickly iterate through different potential versions of their scene. I've looked through the sdk and the different manuals that are available and I believe I understand the processes required.

    My issue comes in with the amount of time it take Cinema to run my plugin in regards to the creation of the Takes and if this is just the time that it takes to create them.

    I created a simple scene with a hundred objects underneath my plugin. With the code below I create a Take and assign a layer to each of the child objects. For time testing I create an additional 500 Takes using the first Take as the cloneFrom inside AddTake. This isn't a final version of my code just a test example.

    The code is executed on a button press.

    
    			case idRunTakes:
    			{
    				TakeData* takeData = doc->GetTakeData();
    				if (!takeData)
    					return TRUE;
    
    				LayerObject *hideLayer = LayerObject::Alloc();
    
    				const Vector hsv = Vector(1.0, 0, 0);
    				const Vector rgb = HSVToRGB(hsv);
    				newTakeTime = 0;
    				settingTakeTime = 0;
    				LayerData newdata;
    				newdata.color = rgb;
    				newdata.solo = FALSE;
    				newdata.view = FALSE;
    				newdata.render = FALSE;
    				newdata.manager = TRUE;
    				newdata.locked = FALSE;
    				newdata.generators = FALSE;
    				newdata.deformers = FALSE;
    				newdata.expressions = FALSE;
    				newdata.animation = FALSE;
    				newdata.xref = TRUE;
    				hideLayer->SetLayerData(doc, newdata);
    				hideLayer->SetName("Hide Layer"_s);
    
    				GeListHead* layerList = NULL;
    				layerList = doc->GetLayerObjectRoot();
    
    				layerList->InsertLast(hideLayer);
    				maxon::BaseArray<BaseObject*> childObjArray;
    				GatherAllChildObjects(splineObj->GetDown(), childObjArray);
    
    				DescID aliasLinkDId = DescLevel(ID_LAYER_LINK, DA_ALIASLINK, 0);
    				GeData setData;
    				setData.SetBaseList2D((BaseList2D*)hideLayer);
    
    				Float createNewTakesTime = 0;
    				Float timeStart = 0;
    				Float loopTimeStart = GeGetMilliSeconds();
    
    				timeStart = GeGetMilliSeconds(); 
    				BaseTake* newTake = takeData->AddTake(String("Take " + String::IntToString(0)), nullptr, nullptr);
    				if (newTake == nullptr)
    					return TRUE;
    
    				createNewTakesTime = createNewTakesTime + GeGetMilliSeconds() - timeStart;
    				for (Int32 childObjIndex = 0; childObjIndex < childObjArray.GetCount(); childObjIndex++)
    				{
    					BaseOverride* overrideNode = newTake->FindOrAddOverrideParam(takeData, childObjArray[childObjIndex], aliasLinkDId, setData);
    					if (overrideNode == nullptr)
    						return TRUE;
    
    					childObjArray[childObjIndex]->SetLayerObject(hideLayer);
    					overrideNode->UpdateSceneNode(takeData, aliasLinkDId);
    				}
    
    
    				for (Int32 takeIndex = 1; takeIndex < 501; takeIndex++)
    				{
    					timeStart = GeGetMilliSeconds();
    // This is the line taking up a lot of time
    					BaseTake* loopTake = takeData->AddTake(String("Take " + String::IntToString(takeIndex)), nullptr, newTake);
    					if (loopTake == nullptr)
    						return TRUE;
    					createNewTakesTime = createNewTakesTime + GeGetMilliSeconds() - timeStart;
    					
    				}
    				ApplicationOutput("Take time " + String::FloatToString(createNewTakesTime) + "    " + String::FloatToString(GeGetMilliSeconds() - loopTimeStart - createNewTakesTime));
    				break;
    			}
    
    
    // Code for getting all of the child objects
    void TakeCreatorPlugin::GatherAllChildObjects(BaseObject *childObject, maxon::BaseArray<BaseObject*> &objChildOfNullsArray)
    {
    	if (childObject == nullptr)
    		return;
    
    	while (childObject)
    	{
    		objChildOfNullsArray.Append(childObject);
    
    
    		GatherAllChildObjects(childObject->GetDown(), objChildOfNullsArray);
    		childObject = childObject->GetNext();
    	}
    }
    

    Running the code in my test scene gives the following print out "Take time 1920.243 20.232". So most of the time my plugin is running is taken up by adding the takes into the document. Is this just the time that Cinema takes in this kind of circumstance to create the Takes or am I just missing a crucial step,

    I've looked through the manuals in the sdk and tried to follow them.

    I've also tried to create all of the Takes empty and add the Overrides to each one individually which increases the time that step takes which isn't desirable either.

    Any help would be greatly appreciated.

    JohnTerenece

    posted in Cinema 4D SDK •
    Effector Updates

    Hello,

    I am working on a plugin that uses an In/Exclude list that the user will fill with Effectors and then I will use the new position provided from the Effectors to do other things.

    My issue comes in when I initially drop an Effector into the In/Exclude while in R25. The initial values that I get from the Effectors are different than the ones I get from the next time it runs on a refresh.

    This isn't an issue in other versions of Cinema because the code runs again immediately with the expected Effector values, meanwhile in R25 it doesn't run a second time until something causes a Cinema refresh which would cause a visual problem in my full plugin because the Effector values are not correct.

    Video of the issue in R25

    Running same circumstance in R23

    I've only run into this issue in R25 with this particular In/Exclude for Effectors, in R25 with an In/Exclude for BaseObjects I haven't had this refresh issue. In R20 through R24 I haven't had this issue with any In/Exclude.

    Below is the complete code trimmed down with the problem with the points shown via prints.

    #define ID_EFFECTORTEST 1055750
    
    #include "c4d.h"
    #include "c4d_gui.h"
    #include "c4d_baseeffectordata.h"
    #include "customgui_inexclude.h"
    
    class EffectorTestClass : public ObjectData
    {
    	INSTANCEOF(EffectorTestClass, ObjectData)
    
    public:
    	virtual Bool Init(GeListNode* node);
    	virtual Bool Message(GeListNode* node, Int32 type, void* data);
    	virtual SplineObject* GetContour(BaseObject* op, BaseDocument* doc, Float lod, BaseThread* bt);
    	virtual void CheckDirty(BaseObject *op, BaseDocument *doc);
    	static NodeData* Alloc() { return NewObjClear(EffectorTestClass); }
    	virtual Bool GetDDescription(GeListNode *node, Description *description, DESCFLAGS_DESC &flags);
    	virtual void RunEffectors(BaseObject *op, BaseDocument *doc, PolygonObject *poly);
    
    	maxon::BaseArray<BaseObject*> compareDirtyObj;
    	maxon::BaseArray<UInt32> dirtyNumber;
    
    	maxon::Result<void> resultVoid;
    	maxon::Result<Int32> resultInt;
    	maxon::Result<Vector> resultVector;
    	maxon::Result<BaseObject*> resultBaseObject;
    
    	UInt32 opDirtyCount = 0;
    };
    
    
    enum Controls
    {
    	idMainTab = 100000,
    	idEffectorList,
    
    };
    
    Bool EffectorTestClass::Message(GeListNode* node, Int32 type, void* data)
    {
    	return SUPER::Message(node, type, data);
    }
    
    Bool EffectorTestClass::GetDDescription(GeListNode *node, Description *description, DESCFLAGS_DESC &flags)
    {
    	BaseContainer *datainstance;
    	const DescID *singleid;
    	if (!description->LoadDescription(node->GetType()))
    	{
    	}
    
    	datainstance = ((BaseList2D*)node)->GetDataInstance();
    	if (!datainstance)
    		return FALSE;
    	singleid = description->GetSingleDescID();
    	DescID cid;
    
    	DescID DescMainTabGroup = DescLevel(idMainTab, DTYPE_GROUP, 0);
    	if (!singleid || DescMainTabGroup.IsPartOf(*singleid, NULL))
    	{
    		BaseContainer bc;
    		bc = GetCustomDataTypeDefault(DTYPE_GROUP);
    		bc.SetString(DESC_NAME, "Effector Test"_s);
    
    		bc.SetInt32(DESC_COLUMNS, 1);
    		bc.SetInt32(DESC_DEFAULT, 1);
    		bc.SetBool(DESC_SCALEH, TRUE);
    
    		if (!description->SetParameter(DescMainTabGroup, bc, DescLevel(ID_EFFECTORTEST)))
    			return TRUE;
    	}
    
    	cid = DescLevel(idEffectorList, CUSTOMDATATYPE_INEXCLUDE_LIST, 0);
    	if (!singleid || cid.IsPartOf(*singleid, NULL))
    	{
    		BaseContainer bc;
    		bc = GetCustomDataTypeDefault(CUSTOMGUI_INEXCLUDE_LIST);
    
    		bc.SetString(DESC_NAME, "Effectors"_s);
    		BaseContainer acceptedObjects;
    		acceptedObjects.InsData(Obaseeffector, String());
    		acceptedObjects.InsData(Oweighteffector, String());
    
    		bc.SetInt32(IN_EXCLUDE_FLAG_INIT_STATE, 3);
    		bc.SetInt32(IN_EXCLUDE_FLAG_NUM_FLAGS, 2);
    		bc.SetInt32(IN_EXCLUDE_FLAG_IMAGE_01_ON, 300000131);
    		bc.SetInt32(IN_EXCLUDE_FLAG_IMAGE_01_OFF, 300000130);
    		bc.SetContainer(DESC_ACCEPT, acceptedObjects);
    		bc.SetBool(IN_EXCLUDE_FLAG_SEND_SELCHANGE_MSG, true);
    
    		bc.SetInt32(IN_EXCLUDE_FLAG_BIG_MODE_SIZE, 150);
    		if (!description->SetParameter(cid, bc, DescMainTabGroup))
    			return TRUE;
    	}
    
    	flags |= DESCFLAGS_DESC::LOADED | DESCFLAGS_DESC::RECURSIONLOCK;
    
    	return SUPER::GetDDescription(node, description, flags);
    }
    
    // Check if the child object, In/Exclude objects have been changed
    void EffectorTestClass::CheckDirty(BaseObject *op, BaseDocument *doc)
    {
    	if (doc == nullptr || op == nullptr)
    		return;
    
    	Bool setDirty = FALSE;
    	BaseContainer docdata = doc->GetData(DOCUMENTSETTINGS::GENERAL);
    	if (docdata == BaseContainer())
    		return;
    
    	BaseContainer *dataInstance = op->GetDataInstance();
    
    	maxon::BaseArray<BaseObject*> objArray;
    
    	if (op->GetDown() != nullptr)
    		resultBaseObject = objArray.Append(op->GetDown());
    
    	GeData tempdata;
    	dataInstance->GetParameter(idEffectorList, tempdata);
    	InExcludeData* data = static_cast<InExcludeData*>(tempdata.GetCustomDataType(CUSTOMDATATYPE_INEXCLUDE_LIST));
    	if (data != nullptr)
    	{
    		Int32 flags = 0;
    		for (Int32 objIndex = 0; objIndex < data->GetObjectCount(); objIndex++)
    		{
    			BaseObject* object = static_cast<BaseObject*>(data->ObjectFromIndex(doc, objIndex));
    			if (object != nullptr)
    			{
    				if (object->GetDeformMode())
    				{
    
    					flags = data->GetFlags(doc, object);
    					if ((flags & 1) == 1)
    					{
    						resultBaseObject = objArray.Append(object);
    					}
    				}
    			}
    		}
    	}
    
    	if (Int32(objArray.GetCount()) != Int32(compareDirtyObj.GetCount()))
    	{
    		setDirty = TRUE;
    		dirtyNumber.Reset();
    	}
    
    	if (Int32(dirtyNumber.GetCount()) != Int32(objArray.GetCount()))
    	{
    		for (Int32 objIndex = Int32(dirtyNumber.GetCount()); objIndex < Int32(objArray.GetCount()); objIndex++)
    			resultInt = dirtyNumber.Append(0);
    	}
    
    	compareDirtyObj.Reset();
    	resultVoid = compareDirtyObj.CopyFrom(objArray);
    
    	for (Int32 index = 0; index < Int32(objArray.GetCount()); index++)
    	{
    		if (dirtyNumber[index] != objArray[index]->GetDirty(DIRTYFLAGS::DATA | DIRTYFLAGS::MATRIX | DIRTYFLAGS::CHILDREN | DIRTYFLAGS::CACHE))
    			setDirty = TRUE;
    
    		dirtyNumber[index] = objArray[index]->GetDirty(DIRTYFLAGS::DATA | DIRTYFLAGS::MATRIX | DIRTYFLAGS::CHILDREN | DIRTYFLAGS::CACHE);
    
    	}
    	if (setDirty == TRUE || opDirtyCount != op->GetDirty(DIRTYFLAGS::MATRIX | DIRTYFLAGS::DATA))
    	{
    		opDirtyCount = op->GetDirty(DIRTYFLAGS::MATRIX | DIRTYFLAGS::DATA);
    		op->SetDirty(DIRTYFLAGS::DATA | DIRTYFLAGS::CACHE);
    
    	}
    }
    
    SplineObject* EffectorTestClass::GetContour(BaseObject* op, BaseDocument* doc, Float lod, BaseThread* bt)
    {
    	PolygonObject *testObj = (PolygonObject*)op->GetDown();
    	if (testObj)
    	{
    		RunEffectors(op, doc, testObj);
    	}
    	opDirtyCount = op->GetDirty(DIRTYFLAGS::MATRIX | DIRTYFLAGS::DATA);
    	SplineObject * returnSpline = SplineObject::Alloc(0, SPLINETYPE::LINEAR);
    	return returnSpline;
    
    }
    
    Bool EffectorTestClass::Init(GeListNode* node)
    {
    	opDirtyCount = 0;
    	return true;
    }
    
    
    void EffectorTestClass::RunEffectors(BaseObject *op, BaseDocument *doc, PolygonObject *poly)
    {
    	BaseContainer *dataInstance = op->GetDataInstance();
    	maxon::BaseArray<Vector> originalCenterPoint;
    
    	const CPolygon *polyArray = poly->GetPolygonR();
    
    	if (polyArray == nullptr)
    	{
    		return;
    	}
    
    	Matrix objMx = poly->GetMg();
    	BaseObject *obj = (BaseObject*)Get();
    	BaseTag * motag = obj->GetTag(ID_MOTAGDATA);
    	if (motag == nullptr)
    		motag = obj->MakeTag(ID_MOTAGDATA);
    	if (motag == nullptr)
    	{
    		return;
    	}
    	BaseTag * polyObjMocacheTag = obj->GetTag(ID_MOBAKETAG);
    
    	GetMoDataMessage modataMsg = GetMoDataMessage();
    	modataMsg.index = 0;
    
    	if (polyObjMocacheTag)
    	{
    		polyObjMocacheTag->Message(MSG_GET_MODATA, &modataMsg);
    	}
    	BaseTag *objTag = obj->GetTag(ID_MOTAGDATA);
    	if (objTag)
    		objTag->Message(MSG_GET_MODATA, &modataMsg);
    
    	if (!modataMsg.modata)
    	{
    		if (!motag->Message(MSG_GET_MODATA, &modataMsg) || !modataMsg.modata)
    		{
    			return;
    		}
    	}
    
    	Float startingTimeA = GeGetMilliSeconds();
    	MoData *md = modataMsg.modata;
    
    	if (md)
    	{
    
    		maxon::BaseArray<Vector> centerPointArray;
    
    		maxon::BaseArray< maxon::BaseArray<Vector> > polyPointArray;
    		maxon::BaseArray<Vector> originalCenterArray;
    		md->GetAutoLock();
    		MDArray<Matrix> matrixArray;
    		maxon::BaseArray<Matrix> originalMatrixArray;
    
    		Int32 polygonCount = poly->GetPolygonCount();
    		Int32 pointCount = poly->GetPointCount();
    		const CPolygon* polygons = poly->GetPolygonR();
    		const Vector *posArray = poly->GetPointR();
    
    		
    		// Get the center points of the various polygons
    		for (Int32 polyIndex = 0; polyIndex < polygonCount; polyIndex++)
    		{
    
    			Vector centerPointOfPolygon = Vector(0);
    			if (polygons[polyIndex].c == polygons[polyIndex].d)
    			{
    				centerPointOfPolygon += posArray[polygons[polyIndex].a];
    				centerPointOfPolygon += posArray[polygons[polyIndex].b];
    				centerPointOfPolygon += posArray[polygons[polyIndex].c];
    
    				centerPointOfPolygon = (centerPointOfPolygon / 3.0);
    
    			}
    			else
    			{
    				centerPointOfPolygon += posArray[polygons[polyIndex].a];
    				centerPointOfPolygon += posArray[polygons[polyIndex].b];
    				centerPointOfPolygon += posArray[polygons[polyIndex].c];
    				centerPointOfPolygon += posArray[polygons[polyIndex].d];
    
    				centerPointOfPolygon = (centerPointOfPolygon / 4.0);
    			}
    			centerPointOfPolygon = Vector(polyIndex * 10, polyIndex * 10, polyIndex * 10);
    
    			resultVector = originalCenterPoint.Append(centerPointOfPolygon);
    			resultVector = centerPointArray.Append(centerPointOfPolygon);
    		}
    
    		md->SetCount(Int32(centerPointArray.GetCount()));
    		matrixArray = md->GetMatrixArray(MODATA_MATRIX);
    
    		MDArray<Vector> setMtxColorArray = md->GetVectorArray(MODATA_COLOR);
    		MDArray<Vector> setMtxColorArra2y = md->GetVectorArray(MODATA_COLOR);
    
    		dataInstance = op->GetDataInstance();
    		const CustomDataType * effectorsraw = dataInstance->GetCustomDataType(idEffectorList, CUSTOMDATATYPE_INEXCLUDE_LIST);
    		InExcludeData * effectors = nullptr;
    		if (effectorsraw)
    			effectors = (InExcludeData*)effectorsraw;
    
    		resultVoid = originalMatrixArray.Resize(Int32(centerPointArray.GetCount()));
    		// Generate the matrices
    		for (Int32 centerIndex = 0; centerIndex < Int32(centerPointArray.GetCount()); centerIndex++)
    		{
    			Vector normal = CalcFaceNormal(posArray, polyArray[centerIndex]);
    
    			Vector upVector = Vector(0, 1, 0);
    
    			normal = normal;
    			normal.Normalize();
    			if (1.0 - abs(Dot(normal, upVector)) < .003)
    			{
    				upVector = Vector(0, 0, -1);
    
    			}
    			Vector z = normal;
    			z.Normalize();
    			Vector temp = Cross(upVector, z);
    
    			Vector y = Cross(z, temp);
    			y.Normalize();
    
    			Vector x = Cross(y, z);
    			x.Normalize();
    
    			matrixArray[centerIndex] = Matrix(centerPointArray[centerIndex], x, y, z);
    		}
    
    		// Runs through the effectors
    		if (effectors)
    		{
    			Effector_PassData emsg = Effector_PassData();
    			emsg.op = op;
    			emsg.md = md;
    			emsg.weight = 1.0;
    			emsg.thread = nullptr;
    			Int32 flags = 0;
    			for (Int i = 0; i < effectors->GetObjectCount(); i++)
    			{
    				BaseObject * e = (BaseObject*)effectors->ObjectFromIndex(doc, i);
    				if (!e)
    					continue;
    				if (!e->GetDeformMode())
    					continue;
    				flags = effectors->GetFlags(doc, e);
    				if (e != nullptr && e->GetDeformMode() == true && (flags & 1) == 1)
    				{
    					e->Message(MSG_EXECUTE_EFFECTOR, &emsg);
    				}
    			}
    		}
    
    		MDArray<Matrix> itemsMtxArray = md->GetMatrixArray(MODATA_MATRIX);
    		Int32 matrixItemCnt = Int32(md->GetCount());
    		ApplicationOutput("New run");
    		for (Int32 centerIndex = 0; centerIndex < matrixItemCnt; centerIndex++)
    			ApplicationOutput("Effector pos " + String::VectorToString(itemsMtxArray[centerIndex].off));
    
    	}
    	return;
    }
    
    
    
    
    Bool RegisterEffectorTest(Bool hideplugin)
    {
    	return RegisterObjectPlugin(ID_EFFECTORTEST, "Effector Move"_s, OBJECT_GENERATOR | OBJECT_ISSPLINE | OBJECT_INPUT, EffectorTestClass::Alloc, "OEffectorTest"_s, AutoBitmap("circle.tif"_s), 0);
    }
    
    

    I am confused what the difference between R23 and R25 could be that is responsible for the latest version not to work the same way or is it purely coincidental that my R23 version worked?

    Any help would be greatly appreciated.

    John Terenece

    posted in Cinema 4D SDK •
    RE: Mograph Effector List

    Thanks for the response.

    I figured it would need to be the SceneHook but always best to double check.

    John Terenece

    posted in Cinema 4D SDK •