Unregister a RedrawViewsCallback in scripted modifier


#1

Having an issue with unregistering a redraw viewport callback that was created in a scripted modifier.
It seems to create an instance of the callback for every object that has a the modifier which I’m guessing is the correct way it is supposed to function. I can also unregister the callback from the modifier.

My problem is unregistering it without the modifier, like when a new scene is loaded and the callback remains but the object that was used to create it is no longer there.

My second problem is even if I could access it, what would be the best way to remove it when loading a new scene? Registering a filepreopen callback?

Below is the code I am using to test.

plugin modifier TestAttributes
    name:"Test Attributes"
    classID:#(685321,452287)
    extends:EmptyModifier
    replaceUI:true
    (
    	parameters main rollout:params
    	(
    		showPosPoint_btn type:#boolean animatable:false ui:showPosPoint_btn default:false
    	)
	
	rollout params "Test Properties"
	(
		checkbutton  showPosPoint_btn " Display Position Points "	checked:false 
		
		global GW_displayObjectNames
		fn GW_displayObjectNames =
		(
			gw.setTransform (matrix3 1)
			for o in objects where not o.isHiddenInVpt do
				gw.text o.pos (o as string) color:yellow
			gw.enlargeUpdateRect #whole
		)

		on showPosPoint_btn changed state do
		(
			if state == true then
			(
				registerRedrawViewsCallback GW_displayObjectNames
			)
			else
			(
				unregisterRedrawViewsCallback GW_displayObjectNames
			)
		)
		
	)
	
)

#2

Hi,
Did you get a chance to find a solution? I am facing the same problem here.
My temporary solution is:

for o in SELECTION where not o.isHiddenInVpt do…

on Dialog open do
(
case chk_button.state of
(
true: (registerRedrawViewsCallback function)
false: (unregisterRedrawViewsCallback function)
)
on Dialog close do
(
unregisterRedrawViewsCallback function
)


#3

This is my working pattern:

try(DestroyDialog TestRol)catch()
rollout TestRol "Callback Test"
(
	checkButton 'ckb_Activate' "Activate"
	
	global CallbackFunction
	
	fn InitializeCallback =
	(
		if CallbackFunction == undefined do
		(
			fn CallbackFunction = undefined
			fn functionPointer = CallbackFunction()
			registerRedrawViewsCallback functionPointer
		)
	)
	
	fn AddCallback =
	(
		fn CallbackFunction = print localTime
	)
	
	fn RemoveCallback =
	(
		fn CallbackFunction = undefined
	)
	
	on ckb_Activate changed state do
	(
		if state == true then
		(
			AddCallback()
		)
		else
		(
			RemoveCallback()
		)
	)
	
	on TestRol open do
	(
		InitializeCallback()
	)
	
	on TestRol close do
	(
		RemoveCallback()
	)
)
CreateDialog TestRol

#4
delete objects

for k=1 to 30 do (dummy pos:(random -[100,100,100] [100,100,100]))


	
try(destroydialog NodeNames_Dialog) catch()
rollout NodeNames_Dialog "Node Names" width:191
(
	checkbutton active_ch "Active" width:173 align:#right offset:[4,10] 

	fn show_names = 
	(
		gw.setTransform (matrix3 1)
		for node in selection where not node.isHiddenInVpt do
		(
			if (pos = gw.htransPoint node.pos) != undefined do -- we need this check in case of Nitrous Progressive mode
			(
				gw.htext pos node.name color:yellow
			)
		)
		gw.enlargeUpdateRect #whole
		gw.updateScreen()
	)
		
	on active_ch changed state do 
	(
		(if state then registerRedrawViewsCallback else unregisterRedrawViewsCallback) ::NodeNames_Dialog.show_names  
	)

	on NodeNames_Dialog close do
	(
		unregisterRedrawViewsCallback ::NodeNames_Dialog.show_names
	)
	on NodeNames_Dialog open do
	(
		unregisterRedrawViewsCallback ::NodeNames_Dialog.show_names
	)
)
createdialog NodeNames_Dialog

i don’t see any reason to have this functionality as a part of any plugin (custom attribute). More likely it should be a macroaction (macrobutton).


#5

the worse problem for this kind of viewport drawings is memory leaking … it’s caused by two things:
#1 in progressive nitrous mode the redraw is called many and many times
#2 gw is a Struct and calling any function from it as “gw.” cases a memory leak.

so we have to minimize the leaking. what can we do?

#1 use very well know trick (use a pointer to struct function):

setTransform = gw.setTransform
htransPoint = gw.htransPoint
htext = gw.htext
enlargeUpdateRect = gw.enlargeUpdateRect
updateScreen = gw.updateScreen

#2 hash and use all previously ‘drawn’ data and update it when anything was changed (selection, node visibility, node names, transforms, etc.)


#6

Thank you for sharing, I will test it


#7

Yeah, I did end up solving the issue a while back. I didn’t know the well known trick of pointer function but that is what I ended up discovering for myself. My solution was very similar too what MZ proposed.