Notifications
Clear all

[Closed] node instances don't keep Custom Attributes instances ?

I have a tool which uses custom attributes applied on nodes to sort them in some kind of groups (nevermind). To achieve this, nodes in the same “group” carry one same single instance of a specific CA.

Problem is, when user clone a node (copy, instance, or reference), the cloned node does not get the CA instance but create a new CA instance instead, leading the cloned node not being “attribute-linked” to the same group as the node it was copied from.

Here is a sample code showing the thing:

(
	-- CA definition
	global CA_Test_Def = attributes "CA_Test" (parameters params (caParamAttr type:#string default:"defaultValue"))
	
	-- struct in the global scope reachable by the callback
	struct myTool (
		fn toolCallback_SceneNodeAdded cbparams =	(
			format "node added: %
" cbparams	-- note that the node name here is not yet changed because the callback #nodeNameSet is called after
		),
		
		on create do (
			-- register the callback 
			try (callbacks.removeScripts id:#test_ca) catch()
			callbacks.addScript #sceneNodeAdded "gMyTool.toolCallback_SceneNodeAdded (callbacks.notificationParam())" id:#test_ca
		)
	)
	global gMyTool = myTool()
	
	--====================================
	-- test scene
	delete objects
	clearListener()
	
	boxOrig = box name:"box_original"
	append boxOrig.custattributes (createInstance CA_Test_Def)	-- For some reason, I need one unique instance for the original and the cloned node
	
	copiedNodes
	maxOps.CloneNodes boxOrig cloneType:#instance newNodes:&copiedNodes
	boxInstance = copiedNodes[1]
	boxInstance.name = "box_copy"
	move boxInstance [-50,0,0]
	
	-- boxInstance.custattributes[1] = boxOrig.custattributes[1]	-- this line instantiate the CA correctly
	
	boxOrig.caParamAttr = "changed caParamAttr value"	--this should change both boxOrig and boxCopy values if their CAs was one single instance
	
	format "boxOriginal ca value: %
" boxOrig.caParamAttr
	format "boxInstance ca value: %
" boxInstance.caParamAttr
	
	callbacks.removeScripts id:#test_ca
	
	OK
)

My tool has only access to the copied node in the #sceneNodeAdded callback.
I cannot maually overwrite the CA with the CA instance of the original because I don’t know it in this callback.

Any pro-tip here to instantiate the CA nicely inside the #sceneNodeAdded callback ?
Thank you all !

PS : To anticipate questions :), I used #sceneNodeAdded instead of #nodeCloned to handle some weird operations like undoing the delete of a node or some others crazy combination to handle in code.

14 Replies

I hate when you search several hours an answer then find it when you just post it on CgTalk forum…

Answer is here:
http://forums.cgsociety.org/showthread.php?t=763883

replacing append boxOrig.baseobject.custattributes (createInstance CA_Test_Def)
by append boxOrig.baseobject.custattributes (createInstance CA_Test_Def)

The previous answer (mine) was only solving one part of the problem, btw.

Because… I don’t want my CA to be on the base object !
I need it to be on the node because several instances of the same baseobject can be in two different “ca-groups”. But I want that if you clone a node which is in a “ca-group”, the cloned noded will be automatically added to the same “ca-group”

How to deal with that ? Magic tip needed, please :).


callbacks.removescripts id:#ca_identifier
ca_id = attributes ca_id attribID:#(0xCA,0x1D)
(
	fn replaceThisInstances = 
	(
		for i in (custattributes.getdefinstances (custattributes.getdef this)) do replaceinstances i this
	)
)
fn replaceCAIdentifier = 
(
	node = callbacks.notificationParam()
	if isproperty node #replaceThisInstances do node.replaceThisInstances()
)
callbacks.addscript #nodeCreated "replaceCAIdentifier()" id:#ca_identifier
callbacks.addscript #nodeCloned "replaceCAIdentifier()" id:#ca_identifier

delete objects
(
	b0 = box()
	custattributes.add b0 ca_id
	b1 = copy b0
	format "(copy)		 > are ca instances: %
" (b0.ca_id == b1.ca_id)
	b2 = instance b1
	format "(instance)	 > are ca instances: %
" (b1.ca_id == b2.ca_id)
	maxOps.CloneNodes b2 cloneType:#instance newNodes:&b3
	format "(clone)		 > are ca instances: %
" (b2.ca_id == b3[1].ca_id)
)

you are a smart guy and can get yourself why it works

Nice piece of code, Denis !
I will try it as soon as I’m at my desk.
From what I see without testing, you replace all ca instances of the scene by the original definition as soon as a node is created or cloned. What if I need to sort my nodes inside several different “ca-groups” (therefore several ca instances). As far as I can predict future, your code might break the sorting each time a node is created/cloned, doesn’t it ?
I do some tests and let you know. Thanks a lot.

Trying to play with your code, I have seen something strange :

it seems that doing “custattributes.add node <ca_def>”
is different then doing “append node.custattributes (createInstance <ca_def>)

ca_id = attributes ca_id attribID:#(0xCA,0x1D)
(
	fn replaceThisInstances = (for i in (custattributes.getdefinstances (custattributes.getdef this)) do replaceinstances i this)
)

(
	delete objects
	
	b0 = box()
 	custattributes.add b0 ca_id
	format "custattributes.add: %
" (isproperty b0 #replaceThisInstances)   -- true
	OK
)

(
	delete objects
	
	b0 = box()
	append b0.custattributes (createInstance ca_id)  -- false
	format "append b0.custattributes (createInstance ca_id): %
" (isproperty b0 #replaceThisInstances)
	OK
)

I always thought that custattributes.add did create internally an instance of the CA then appended it to the node but it seems that it doesn’t…
How do you explain that ?

Ok, I had some time again and look at this again.

First, “custattributes.add” adds a CA on the node’s baseobject. That’s why the implicit property doesn’t work when I manually append the CA instance on the node. That answered my previous post.

Second, I need to add attributes on the node and NOT on the baseobject. Denis, I think that your technique doesn’t work in my case. Tell me if I’m wrong after reading the followings.

=============================================

I resume the goal of the tool :

Let’s assume a simple scene with:

  • 4 nodes A B C D all instances (same baseobject)
  • 2 “ca-groups” represented by 2 CA instances (caInst1 and caInst2)

Basic rules:

several different instances of the CA in the scene

each of these instances is carried by several nodes (caInst1 on node A and B, caInst2 on node C and D)

two instances of the same object can carry differents CA instances (therefore the CA is on the node and NOT on the baseobject)

one node can carry only one single instance

My problem:

  • a copy, instance, reference of a node will create a new CA instance on the node (because it is carried by the node and not by the baseobject)
  • how can I be sure that a cloned node will carry the instance of the original node from which it was cloned ??

PS: That’s what my first post should have been…

  • 2 “ca-groups” represented by 2 CA instances (caInst1 and caInst2)

do these CAs have the same definition?

Yes, they have.

why do you not want to add the CA to the baseobject?

Page 1 / 2