Viewport Redraw Callback Mechanism

 

   

Callback Notifications - Quick Navigation

You can register one or more functions to be called whenever the 3ds Max viewports are redrawn.

In addition, with the introduction of the Nitrous Graphics Manager in 3ds Max 2012, any MAXScript Graphics Window (gw.) Viewport Drawing Methods must be wrapped in a Viewport Redraw Callback function to produce any results due to the progressive refinement nature of the drawing process.

The following methods let you register and unregister these callbacks:

registerRedrawViewsCallback <fn>
unRegisterRedrawViewsCallback <fn>

You can register as many functions as you like. Each one is individually called whenever the viewports are redrawn. The functions you register must take no arguments.

EXAMPLE:

fn redrawviews_p = print "Viewports Redrawn"
registerRedrawViewsCallback redrawviews_p

In the above example, the registered function causes the string "Viewports Redrawn" to be printed in the Listener window whenever the 3ds Max viewports are redrawn.

Special Considerations

EXAMPLE:

fn redrawviews_cb = print currentTime
fn rvcb = redrawviews_cb()
registerRedrawViewsCallback rvcb

In this case, the registered callback function, rvcb , calls the real call back, redrawviews_cb , (by referencing the global variable it is defined in), meaning you can redefine redrawviews_cb() as often as you need and the callback will always invoke the latest definition. This is a useful technique to employ while you are developing and debugging a callback.

Note that you may only redefine the redrawviews_cb() function but NOT evaluate the other two lines again, otherwise you would end up with multiple callbacks calling the same function on each redraw.

EXAMPLE:

unregisterRedrawViewsCallback redrawviews_callback_function
fn redrawviews_callback_function = print "Viewport Redraw 1"
registerRedrawViewsCallbackredrawviews_callback_function

Evaluating the above will first attempt to unregister the callback function. If it was not registered, nothing will happen. Then the function will be defined and its value will be registered as callback. Orbiting in the viewport for example will cause the string to be printed to the listener.

If you would change the string to "Viewport Redraw 2" and evaluate the same code, the old function will be unregistered, the new function will be defined and the new callback will be registered. Orbiting the viewport will print the new string only.

BAD EXAMPLE:

fn redrawviews_callback_function = print "Viewport Redraw2"
unregisterRedrawViewsCallback redrawviews_callback_function
registerRedrawViewsCallback redrawviews_callback_function

If the unregister function call were the second line and not the first, the new function would be defined first, then the unregister attempt would fail silently because the new function would be used and the old one's value would be inaccessible. This would result in both the old and the new functions being executed on viewport redraws, thus printing both "Viewport Redraw 1" and "Viewport Redraw 2" to the Listener.

LOCAL SCOPE EXAMPLE:

(--open a local scope
global redrawviews_cb_function --ensure variable visibility
unregisterRedrawViewsCallback redrawviews_cb_function
fn redrawviews_cb_function= print "Redraw Test1"
registerRedrawViewsCallback redrawviews_cb_function
)--end local scope

If the function definition and the callback unregistering and registering are performed in local scope, it is paramount to ensure the callback function's visibility to the code in either global scope or a "private local" scope such as the top-level local scope of a MacroScript that would protect the function value during the current session. Evaluating the above code without a global declaration would create a function value inside the LOCAL scope defined by the outer-most brackets and the attempt to call unregisterRedrawViewsCallback() in a second evaluation of the script would NOT see the original function value in the variable since the variable would have ceased to exist after the first run. Thus, the variable storing the function value must be declared as global to allow a second run of the script to successfully unregister the previous function value.

Changing the printed string to "Redraw Test 2" and evaluating the code again would correctly unregister the old value stored in the global variable, then overwrite it with the new value and register it as a redraw views callback.

 

   

Callback Notifications - Quick Navigation

See Also