2021-11-07 23:43:01 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
# ifdef NEW_DIRECTLINK_PLUGIN
# include "DatasmithMaxDirectLink.h"
# include "Logging/LogMacros.h"
# include "Windows/AllowWindowsPlatformTypes.h"
MAX_INCLUDES_START
# include "max.h"
# include "notify.h"
# include "ISceneEventManager.h"
MAX_INCLUDES_END
namespace DatasmithMaxDirectLink
{
// This is used to handle some of change events
class FNodeEventCallback : public INodeEventCallback
{
ISceneTracker & SceneTracker ;
public :
FNodeEventCallback ( ISceneTracker & InSceneTracker ) : SceneTracker ( InSceneTracker )
{
}
virtual BOOL VerboseDeleted ( ) { return TRUE ; }
virtual void GeometryChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " GeometryChanged " , nodes ) ;
for ( int NodeIndex = 0 ; NodeIndex < nodes . Count ( ) ; + + NodeIndex )
{
SceneTracker . NodeGeometryChanged ( nodes [ NodeIndex ] ) ;
}
}
// Fired when node transform changes
virtual void ControllerOtherEvent ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " ControllerOtherEvent " , nodes ) ;
for ( int NodeIndex = 0 ; NodeIndex < nodes . Count ( ) ; + + NodeIndex )
{
SceneTracker . NodeTransformChanged ( nodes [ NodeIndex ] ) ;
}
}
// Tracks material assignment on node
virtual void MaterialStructured ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " MaterialStructured " , nodes ) ;
for ( int NodeIndex = 0 ; NodeIndex < nodes . Count ( ) ; + + NodeIndex )
{
SceneTracker . NodeMaterialAssignmentChanged ( nodes [ NodeIndex ] ) ;
}
}
// Tracks node's material parameter change(even if it's a submaterial of multimat that is assigned)
virtual void MaterialOtherEvent ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " MaterialOtherEvent " , nodes ) ;
for ( int NodeIndex = 0 ; NodeIndex < nodes . Count ( ) ; + + NodeIndex )
{
SceneTracker . NodeMaterialGraphModified ( nodes [ NodeIndex ] ) ;
}
}
virtual void HideChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " HideChanged " , nodes ) ;
for ( int NodeIndex = 0 ; NodeIndex < nodes . Count ( ) ; + + NodeIndex )
{
SceneTracker . NodeHideChanged ( nodes [ NodeIndex ] ) ;
}
}
virtual void RenderPropertiesChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " RenderPropertiesChanged " , nodes ) ;
// Handle Renderable flag change. mxs: box.setRenderable
for ( int NodeIndex = 0 ; NodeIndex < nodes . Count ( ) ; + + NodeIndex )
{
SceneTracker . NodePropertiesChanged ( nodes [ NodeIndex ] ) ;
}
}
2021-11-18 14:37:34 -05:00
virtual void UserPropertiesChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " UserPropertiesChanged " , nodes ) ;
// Handle user properties change for metadata update
for ( int NodeIndex = 0 ; NodeIndex < nodes . Count ( ) ; + + NodeIndex )
{
SceneTracker . NodePropertiesChanged ( nodes [ NodeIndex ] ) ;
}
}
2021-11-07 23:43:01 -05:00
virtual void NameChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " NameChanged " , nodes ) ;
for ( int NodeIndex = 0 ; NodeIndex < nodes . Count ( ) ; + + NodeIndex )
{
SceneTracker . NodePropertiesChanged ( nodes [ NodeIndex ] ) ;
}
}
2021-11-18 14:37:34 -05:00
virtual void LayerChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " LayerChanged " , nodes ) ;
for ( int NodeIndex = 0 ; NodeIndex < nodes . Count ( ) ; + + NodeIndex )
{
SceneTracker . NodePropertiesChanged ( nodes [ NodeIndex ] ) ;
}
}
2021-11-07 23:43:01 -05:00
// Not used:
virtual void Added ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " Added " , nodes ) ;
}
virtual void Deleted ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " Deleted " , nodes ) ;
}
virtual void LinkChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " LinkChanged " , nodes ) ;
}
virtual void GroupChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " GroupChanged " , nodes ) ;
}
virtual void HierarchyOtherEvent ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " HierarchyOtherEvent " , nodes ) ;
}
virtual void ModelStructured ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " ModelStructured " , nodes ) ;
}
virtual void TopologyChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " TopologyChanged " , nodes ) ;
}
virtual void MappingChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " MappingChanged " , nodes ) ;
}
virtual void ExtentionChannelChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " ExtentionChannelChanged " , nodes ) ;
}
virtual void ModelOtherEvent ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " ModelOtherEvent " , nodes ) ;
}
virtual void ControllerStructured ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " ControllerStructured " , nodes ) ;
}
virtual void WireColorChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " WireColorChanged " , nodes ) ;
}
virtual void DisplayPropertiesChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " DisplayPropertiesChanged " , nodes ) ;
}
virtual void PropertiesOtherEvent ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " PropertiesOtherEvent " , nodes ) ;
}
virtual void SubobjectSelectionChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " SubobjectSelectionChanged " , nodes ) ;
}
virtual void SelectionChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " SelectionChanged " , nodes ) ;
}
virtual void FreezeChanged ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " FreezeChanged " , nodes ) ;
}
virtual void DisplayOtherEvent ( NodeKeyTab & nodes ) override
{
LogNodeEvent ( L " DisplayOtherEvent " , nodes ) ;
}
virtual void CallbackBegin ( ) override
{
LOG_DEBUG_HEAVY ( L " NodeEventCallback: CallbackBegin \n " ) ;
}
virtual void CallbackEnd ( ) override
{
LOG_DEBUG_HEAVY ( L " NodeEventCallback: CallbackEnd \n " ) ;
}
ISceneEventManager : : CallbackKey CallbackKey ;
} ;
// Material changes more precise tracking can be done with ReferenceMaker
// INodeEventCallback's MaterialOtherEvent tracks that any change is done to the material assigned to node
// When a submaterial of a multimat is changed MaterialOtherEvent is called /omitting/ details which submaterial is modified
// ReferenceMaker on the other hand tracks individual (sub)material changes
// todo:
// - stop observing material when not needed(i.e. it's not assigned, used as submaterial or something else(?)
// - remove when deleted
class FMaterialObserver : public ReferenceMaker
{
typedef int FMaterialIndex ;
public :
~ FMaterialObserver ( )
{
DeleteAllRefs ( ) ; // Required to be called in destructor
}
void Reset ( )
{
IndexToReferencedMaterial . Reset ( ) ;
ReferencedMaterialToIndex . Reset ( ) ;
}
RefResult NotifyRefChanged ( const Interval & ChangeInterval , RefTargetHandle TargetHandle , PartID & PartId , RefMessage Message , BOOL propagate ) override
{
// todo: remove material handling???
ensure ( ReferencedMaterialToIndex . Contains ( TargetHandle ) ) ;
LogDebug ( FString : : Printf ( TEXT ( " NotifyRefChanged: %s: %x " ) , dynamic_cast < Mtl * > ( TargetHandle ) - > GetName ( ) . data ( ) , Message ) ) ;
return REF_SUCCEED ;
}
void AddMaterial ( Mtl * Material )
{
if ( ! ReferencedMaterialToIndex . Contains ( Material ) )
{
ReplaceReference ( NumRefs ( ) , Material ) ;
}
}
// todo: unused
// RECONSIDER: when this method is used - removed material reduces NumRefs result so adding new material will overwrite already existing reference
// e.g. was two materials added, with index 0 and 1, material 0 removed, NumRefs becomes 1 so next call ReplaceReference(NumRefs(), Material) will replace material 1 in the map
void RemoveMaterial ( Mtl * Material )
{
FMaterialIndex MaterialIndex ;
if ( ReferencedMaterialToIndex . RemoveAndCopyValue ( Material , MaterialIndex ) )
{
IndexToReferencedMaterial . Remove ( MaterialIndex ) ;
}
}
int NumRefs ( ) override
{
return IndexToReferencedMaterial . Num ( ) ;
}
RefTargetHandle GetReference ( int ReferenceIndex ) override
{
return IndexToReferencedMaterial [ ReferenceIndex ] ;
}
void SetReference ( int ReferenceIndex , RefTargetHandle TargetHandle ) override
{
IndexToReferencedMaterial . Add ( ReferenceIndex , TargetHandle ) ;
ReferencedMaterialToIndex . Add ( TargetHandle , ReferenceIndex ) ;
}
private :
TMap < FMaterialIndex , RefTargetHandle > IndexToReferencedMaterial ;
TMap < RefTargetHandle , FMaterialIndex > ReferencedMaterialToIndex ;
} ;
class FNodeObserver : public ReferenceMaker
{
typedef int FItemIndex ;
public :
~ FNodeObserver ( )
{
DeleteAllRefs ( ) ; // Required to be called in destructor
}
void Reset ( )
{
IndexToReferencedItem . Reset ( ) ;
ReferencedItemToIndex . Reset ( ) ;
}
RefResult NotifyRefChanged ( const Interval & ChangeInterval , RefTargetHandle TargetHandle , PartID & PartId , RefMessage Message , BOOL propagate ) override
{
// todo: remove material handling???
ensure ( ReferencedItemToIndex . Contains ( TargetHandle ) ) ;
LOG_DEBUG_HEAVY ( FString : : Printf ( TEXT ( " FNodeObserver::NotifyRefChanged: %s: %x " ) , dynamic_cast < INode * > ( TargetHandle ) - > GetName ( ) , Message ) ) ; // heavy logging - called a lot
return REF_SUCCEED ;
}
void AddItem ( INode * Node )
{
if ( ! ReferencedItemToIndex . Contains ( Node ) )
{
ReplaceReference ( NumRefs ( ) , Node ) ;
}
}
// todo: unused
// RECONSIDER: when this method is used - removed material reduces NumRefs result so adding new material will overwrite already existing reference
// e.g. was two materials added, with index 0 and 1, material 0 removed, NumRefs becomes 1 so next call ReplaceReference(NumRefs(), Material) will replace material 1 in the map
void RemoveItem ( Mtl * Node )
{
FItemIndex NodeIndex ;
if ( ReferencedItemToIndex . RemoveAndCopyValue ( Node , NodeIndex ) )
{
IndexToReferencedItem . Remove ( NodeIndex ) ;
}
}
int NumRefs ( ) override
{
return IndexToReferencedItem . Num ( ) ;
}
RefTargetHandle GetReference ( int ReferenceIndex ) override
{
RefTargetHandle TargetHandle = IndexToReferencedItem [ ReferenceIndex ] ;
LOG_DEBUG_HEAVY ( FString : : Printf ( TEXT ( " FNodeObserver::GetReference: %d, %s " ) , ReferenceIndex , TargetHandle ? dynamic_cast < INode * > ( TargetHandle ) - > GetName ( ) : TEXT ( " <null> " ) ) ) ;
return TargetHandle ;
}
void SetReference ( int ReferenceIndex , RefTargetHandle TargetHandle ) override
{
LOG_DEBUG_HEAVY ( FString : : Printf ( TEXT ( " FNodeObserver::SetReference: %d, %s " ) , ReferenceIndex , TargetHandle ? dynamic_cast < INode * > ( TargetHandle ) - > GetName ( ) : TEXT ( " <null> " ) ) ) ;
// todo: investigate why NodeEventNamespace::GetNodeByKey may stil return NULL
// testcase - add XRef Material - this will immediately have this
// even though NOTIFY_SCENE_ADDED_NODE was called for node and NOTIFY_SCENE_PRE_DELETED_NODE wasn't!
// BUT SeetReference with NULL handle is called
// also REFMSG_REF_DELETED and TARGETMSG_DELETING_NODE messages are sent to NotifyRefChanged
check ( ! ReferencedItemToIndex . Contains ( TargetHandle ) ) ; // Not expecting to have same handle under two indices(back-indexing breaks)
if ( TargetHandle )
{
ReferencedItemToIndex . Add ( TargetHandle , ReferenceIndex ) ;
}
if ( RefTargetHandle * HandlePtr = IndexToReferencedItem . Find ( ReferenceIndex ) )
{
if ( * HandlePtr )
{
ReferencedItemToIndex . Remove ( * HandlePtr ) ;
}
* HandlePtr = TargetHandle ;
}
else
{
IndexToReferencedItem . Add ( ReferenceIndex , TargetHandle ) ;
}
}
private :
TMap < FItemIndex , RefTargetHandle > IndexToReferencedItem ;
TMap < RefTargetHandle , FItemIndex > ReferencedItemToIndex ;
} ;
FNotifications : : FNotifications ( IExporter & InExporter )
: Exporter ( InExporter )
, NodeObserver ( MakeUnique < FNodeObserver > ( ) )
, MaterialObserver ( MakeUnique < FMaterialObserver > ( ) )
2021-12-06 14:48:33 -05:00
{
RegisterForSystemNotifications ( ) ; // Always follow system events like file reset, new, open and others. But some system notifications also track changes within scene.
}
2021-11-07 23:43:01 -05:00
FNotifications : : ~ FNotifications ( )
{
2021-12-06 14:48:33 -05:00
for ( int Code : NotificationCodesRegistered )
{
UnRegisterNotification ( On3dsMaxNotification , this , Code ) ;
}
NotificationCodesRegistered . Reset ( ) ;
StopSceneChangeTracking ( ) ;
2021-11-07 23:43:01 -05:00
}
void FNotifications : : AddNode ( INode * Node )
{
NodeObserver - > AddItem ( Node ) ;
}
2021-12-06 14:48:33 -05:00
void FNotifications : : RegisterForSystemNotifications ( )
2021-11-07 23:43:01 -05:00
{
// Build todo: remove strings, for debug/logging
# pragma warning(push)
# pragma warning(disable:4995) // disable error on deprecated events, we just assign handlers not firing them
2021-11-18 14:37:34 -05:00
int Codes [ ] = { NOTIFY_UNITS_CHANGE , NOTIFY_TIMEUNITS_CHANGE , NOTIFY_VIEWPORT_CHANGE , NOTIFY_SPACEMODE_CHANGE , NOTIFY_SYSTEM_PRE_RESET , NOTIFY_SYSTEM_POST_RESET , NOTIFY_SYSTEM_PRE_NEW , NOTIFY_SYSTEM_POST_NEW , NOTIFY_FILE_PRE_OPEN , NOTIFY_FILE_POST_OPEN , NOTIFY_FILE_PRE_MERGE , NOTIFY_FILE_POST_MERGE , NOTIFY_FILE_PRE_SAVE , NOTIFY_FILE_POST_SAVE , NOTIFY_FILE_OPEN_FAILED , NOTIFY_FILE_PRE_SAVE_OLD , NOTIFY_FILE_POST_SAVE_OLD , NOTIFY_SELECTIONSET_CHANGED , NOTIFY_BITMAP_CHANGED , NOTIFY_PRE_RENDER , NOTIFY_POST_RENDER , NOTIFY_PRE_RENDERFRAME , NOTIFY_POST_RENDERFRAME , NOTIFY_PRE_IMPORT , NOTIFY_POST_IMPORT , NOTIFY_IMPORT_FAILED , NOTIFY_PRE_EXPORT , NOTIFY_POST_EXPORT , NOTIFY_EXPORT_FAILED , NOTIFY_NODE_RENAMED , NOTIFY_PRE_PROGRESS , NOTIFY_POST_PROGRESS , NOTIFY_MODPANEL_SEL_CHANGED , NOTIFY_RENDPARAM_CHANGED , NOTIFY_MATLIB_PRE_OPEN , NOTIFY_MATLIB_POST_OPEN , NOTIFY_MATLIB_PRE_SAVE , NOTIFY_MATLIB_POST_SAVE , NOTIFY_MATLIB_PRE_MERGE , NOTIFY_MATLIB_POST_MERGE , NOTIFY_FILELINK_BIND_FAILED , NOTIFY_FILELINK_DETACH_FAILED , NOTIFY_FILELINK_RELOAD_FAILED , NOTIFY_FILELINK_ATTACH_FAILED , NOTIFY_FILELINK_PRE_BIND , NOTIFY_FILELINK_POST_BIND , NOTIFY_FILELINK_PRE_DETACH , NOTIFY_FILELINK_POST_DETACH , NOTIFY_FILELINK_PRE_RELOAD , NOTIFY_FILELINK_POST_RELOAD , NOTIFY_FILELINK_PRE_ATTACH , NOTIFY_FILELINK_POST_ATTACH , NOTIFY_RENDER_PREEVAL , NOTIFY_NODE_CREATED , NOTIFY_NODE_LINKED , NOTIFY_NODE_UNLINKED , NOTIFY_NODE_HIDE , NOTIFY_NODE_UNHIDE , NOTIFY_NODE_FREEZE , NOTIFY_NODE_UNFREEZE , NOTIFY_NODE_PRE_MTL , NOTIFY_NODE_POST_MTL , NOTIFY_SCENE_ADDED_NODE , NOTIFY_SCENE_PRE_DELETED_NODE , NOTIFY_SCENE_POST_DELETED_NODE , NOTIFY_SEL_NODES_PRE_DELETE , NOTIFY_SEL_NODES_POST_DELETE , NOTIFY_WM_ENABLE , NOTIFY_SYSTEM_SHUTDOWN , NOTIFY_SYSTEM_STARTUP , NOTIFY_PLUGIN_LOADED , NOTIFY_SYSTEM_SHUTDOWN2 , NOTIFY_ANIMATE_ON , NOTIFY_ANIMATE_OFF , NOTIFY_COLOR_CHANGE , NOTIFY_PRE_EDIT_OBJ_CHANGE , NOTIFY_POST_EDIT_OBJ_CHANGE , NOTIFY_RADIOSITYPROCESS_STARTED , NOTIFY_RADIOSITYPROCESS_STOPPED , NOTIFY_RADIOSITYPROCESS_RESET , NOTIFY_RADIOSITYPROCESS_DONE , NOTIFY_LIGHTING_UNIT_DISPLAY_SYSTEM_CHANGE , NOTIFY_BEGIN_RENDERING_REFLECT_REFRACT_MAP , NOTIFY_BEGIN_RENDERING_ACTUAL_FRAME , NOTIFY_BEGIN_RENDERING_TONEMAPPING_IMAGE , NOTIFY_RADIOSITY_PLUGIN_CHANGED , NOTIFY_SCENE_UNDO , NOTIFY_SCENE_REDO , NOTIFY_MANIPULATE_MODE_OFF , NOTIFY_MANIPULATE_MODE_ON , NOTIFY_SCENE_XREF_PRE_MERGE , NOTIFY_SCENE_XREF_POST_MERGE , NOTIFY_OBJECT_XREF_PRE_MERGE , NOTIFY_OBJECT_XREF_POST_MERGE , NOTIFY_PRE_MIRROR_NODES , NOTIFY_POST_MIRROR_NODES , NOTIFY_NODE_CLONED , NOTIFY_PRE_NOTIFYDEPENDENTS , NOTIFY_POST_NOTIFYDEPENDENTS , NOTIFY_MTL_REFDELETED , NOTIFY_TIMERANGE_CHANGE , NOTIFY_PRE_MODIFIER_ADDED , NOTIFY_POST_MODIFIER_ADDED , NOTIFY_PRE_MODIFIER_DELETED , NOTIFY_POST_MODIFIER_DELETED , NOTIFY_FILELINK_POST_RELOAD_PRE_PRUNE , NOTIFY_PRE_NODES_CLONED , NOTIFY_POST_NODES_CLONED , NOTIFY_SYSTEM_PRE_DIR_CHANGE , NOTIFY_SYSTEM_POST_DIR_CHANGE , NOTIFY_SV_SELECTIONSET_CHANGED , NOTIFY_SV_DOUBLECLICK_GRAPHNODE , NOTIFY_PRE_RENDERER_CHANGE , NOTIFY_POST_RENDERER_CHANGE , NOTIFY_SV_PRE_LAYOUT_CHANGE , NOTIFY_SV_POST_LAYOUT_CHANGE , NOTIFY_BY_CATEGORY_DISPLAY_FILTER_CHANGED , NOTIFY_CUSTOM_DISPLAY_FILTER_CHANGED , NOTIFY_LAYER_CREATED , NOTIFY_LAYER_DELETED , NOTIFY_NODE_LAYER_CHANGED , NOTIFY_TABBED_DIALOG_CREATED , NOTIFY_TABBED_DIALOG_DELETED , NOTIFY_NODE_NAME_SET , NOTIFY_HW_TEXTURE_CHANGED , NOTIFY_MXS_STARTUP , NOTIFY_MXS_POST_STARTUP , NOTIFY_ACTION_ITEM_HOTKEY_PRE_EXEC , NOTIFY_ACTION_ITEM_HOTKEY_POST_EXEC , NOTIFY_SCENESTATE_PRE_SAVE , NOTIFY_SCENESTATE_POST_SAVE , NOTIFY_SCENESTATE_PRE_RESTORE , NOTIFY_SCENESTATE_POST_RESTORE , NOTIFY_SCENESTATE_DELETE , NOTIFY_SCENESTATE_RENAME , NOTIFY_SCENE_PRE_UNDO , NOTIFY_SCENE_PRE_REDO , NOTIFY_SCENE_POST_UNDO , NOTIFY_SCENE_POST_REDO , NOTIFY_MXS_SHUTDOWN , NOTIFY_D3D_PRE_DEVICE_RESET , NOTIFY_D3D_POST_DEVICE_RESET , NOTIFY_TOOLPALETTE_MTL_SUSPEND , NOTIFY_TOOLPALETTE_MTL_RESUME , NOTIFY_CLASSDESC_REPLACED , NOTIFY_FILE_PRE_OPEN_PROCESS , NOTIFY_FILE_POST_OPEN_PROCESS , NOTIFY_FILE_PRE_SAVE_PROCESS , NOTIFY_FILE_POST_SAVE_PROCESS , NOTIFY_CLASSDESC_LOADED , NOTIFY_TOOLBARS_PRE_LOAD , NOTIFY_TOOLBARS_POST_LOAD , NOTIFY_ATS_PRE_REPATH_PHASE , N
# if MAX_PRODUCT_YEAR_NUMBER >= 2018
, NOTIFY_PRE_VIEWPORT_TOOLTIP , NOTIFY_WELCOMESCREEN_DONE , NOTIFY_PLAYBACK_START , NOTIFY_PLAYBACK_END , NOTIFY_SCENE_EXPLORER_NEEDS_UPDATE , NOTIFY_FILE_POST_OPEN_PROCESS_FINALIZED , NOTIFY_FILE_POST_MERGE_PROCESS_FINALIZED
# endif
2021-11-07 23:43:01 -05:00
# if MAX_PRODUCT_YEAR_NUMBER >= 2022
, NOTIFY_PRE_PROJECT_FOLDER_CHANGE , NOTIFY_POST_PROJECT_FOLDER_CHANGE , NOTIFY_PRE_MXS_STARTUP_SCRIPT_LOAD , NOTIFY_ACTIVESHADE_IN_VIEWPORT_TOGGLED , NOTIFY_SYSTEM_SHUTDOWN_CHECK , NOTIFY_SYSTEM_SHUTDOWN_CHECK_FAILED , NOTIFY_SYSTEM_SHUTDOWN_CHECK_PASSED , NOTIFY_FILE_POST_MERGE3 , NOTIFY_ACTIVESHADE_IN_FRAMEBUFFER_TOGGLED , NOTIFY_PRE_ACTIVESHADE_IN_VIEWPORT_TOGGLED , NOTIFY_POST_ACTIVESHADE_IN_VIEWPORT_TOGGLED
# endif
, NOTIFY_INTERNAL_USE_START } ;
2021-11-18 14:37:34 -05:00
FString Strings [ ] = { TEXT ( " NOTIFY_UNITS_CHANGE " ) , TEXT ( " NOTIFY_TIMEUNITS_CHANGE " ) , TEXT ( " NOTIFY_VIEWPORT_CHANGE " ) , TEXT ( " NOTIFY_SPACEMODE_CHANGE " ) , TEXT ( " NOTIFY_SYSTEM_PRE_RESET " ) , TEXT ( " NOTIFY_SYSTEM_POST_RESET " ) , TEXT ( " NOTIFY_SYSTEM_PRE_NEW " ) , TEXT ( " NOTIFY_SYSTEM_POST_NEW " ) , TEXT ( " NOTIFY_FILE_PRE_OPEN " ) , TEXT ( " NOTIFY_FILE_POST_OPEN " ) , TEXT ( " NOTIFY_FILE_PRE_MERGE " ) , TEXT ( " NOTIFY_FILE_POST_MERGE " ) , TEXT ( " NOTIFY_FILE_PRE_SAVE " ) , TEXT ( " NOTIFY_FILE_POST_SAVE " ) , TEXT ( " NOTIFY_FILE_OPEN_FAILED " ) , TEXT ( " NOTIFY_FILE_PRE_SAVE_OLD " ) , TEXT ( " NOTIFY_FILE_POST_SAVE_OLD " ) , TEXT ( " NOTIFY_SELECTIONSET_CHANGED " ) , TEXT ( " NOTIFY_BITMAP_CHANGED " ) , TEXT ( " NOTIFY_PRE_RENDER " ) , TEXT ( " NOTIFY_POST_RENDER " ) , TEXT ( " NOTIFY_PRE_RENDERFRAME " ) , TEXT ( " NOTIFY_POST_RENDERFRAME " ) , TEXT ( " NOTIFY_PRE_IMPORT " ) , TEXT ( " NOTIFY_POST_IMPORT " ) , TEXT ( " NOTIFY_IMPORT_FAILED " ) , TEXT ( " NOTIFY_PRE_EXPORT " ) , TEXT ( " NOTIFY_POST_EXPORT " ) , TEXT ( " NOTIFY_EXPORT_FAILED " ) , TEXT ( " NOTIFY_NODE_RENAMED " ) , TEXT ( " NOTIFY_PRE_PROGRESS " ) , TEXT ( " NOTIFY_POST_PROGRESS " ) , TEXT ( " NOTIFY_MODPANEL_SEL_CHANGED " ) , TEXT ( " NOTIFY_RENDPARAM_CHANGED " ) , TEXT ( " NOTIFY_MATLIB_PRE_OPEN " ) , TEXT ( " NOTIFY_MATLIB_POST_OPEN " ) , TEXT ( " NOTIFY_MATLIB_PRE_SAVE " ) , TEXT ( " NOTIFY_MATLIB_POST_SAVE " ) , TEXT ( " NOTIFY_MATLIB_PRE_MERGE " ) , TEXT ( " NOTIFY_MATLIB_POST_MERGE " ) , TEXT ( " NOTIFY_FILELINK_BIND_FAILED " ) , TEXT ( " NOTIFY_FILELINK_DETACH_FAILED " ) , TEXT ( " NOTIFY_FILELINK_RELOAD_FAILED " ) , TEXT ( " NOTIFY_FILELINK_ATTACH_FAILED " ) , TEXT ( " NOTIFY_FILELINK_PRE_BIND " ) , TEXT ( " NOTIFY_FILELINK_POST_BIND " ) , TEXT ( " NOTIFY_FILELINK_PRE_DETACH " ) , TEXT ( " NOTIFY_FILELINK_POST_DETACH " ) , TEXT ( " NOTIFY_FILELINK_PRE_RELOAD " ) , TEXT ( " NOTIFY_FILELINK_POST_RELOAD " ) , TEXT ( " NOTIFY_FILELINK_PRE_ATTACH " ) , TEXT ( " NOTIFY_FILELINK_POST_ATTACH " ) , TEXT ( " NOTIFY_RENDER_PREEVAL " ) , TEXT ( " NOTIFY_NODE_CREATED " ) , TEXT ( " NOTIFY_NODE_LINKED " ) , TEXT ( " NOTIFY_NODE_UNLINKED " ) , TEXT ( " NOTIFY_NODE_HIDE " ) , TEXT ( " NOTIFY_NODE_UNHIDE " ) , TEXT ( " NOTIFY_NODE_FREEZE " ) , TEXT ( " NOTIFY_NODE_UNFREEZE " ) , TEXT ( " NOTIFY_NODE_PRE_MTL " ) , TEXT ( " NOTIFY_NODE_POST_MTL " ) , TEXT ( " NOTIFY_SCENE_ADDED_NODE " ) , TEXT ( " NOTIFY_SCENE_PRE_DELETED_NODE " ) , TEXT ( " NOTIFY_SCENE_POST_DELETED_NODE " ) , TEXT ( " NOTIFY_SEL_NODES_PRE_DELETE " ) , TEXT ( " NOTIFY_SEL_NODES_POST_DELETE " ) , TEXT ( " NOTIFY_WM_ENABLE " ) , TEXT ( " NOTIFY_SYSTEM_SHUTDOWN " ) , TEXT ( " NOTIFY_SYSTEM_STARTUP " ) , TEXT ( " NOTIFY_PLUGIN_LOADED " ) , TEXT ( " NOTIFY_SYSTEM_SHUTDOWN2 " ) , TEXT ( " NOTIFY_ANIMATE_ON " ) , TEXT ( " NOTIFY_ANIMATE_OFF " ) , TEXT ( " NOTIFY_COLOR_CHANGE " ) , TEXT ( " NOTIFY_PRE_EDIT_OBJ_CHANGE " ) , TEXT ( " NOTIFY_POST_EDIT_OBJ_CHANGE " ) , TEXT ( " NOTIFY_RADIOSITYPROCESS_STARTED " ) , TEXT ( " NOTIFY_RADIOSITYPROCESS_STOPPED " ) , TEXT ( " NOTIFY_RADIOSITYPROCESS_RESET " ) , TEXT ( " NOTIFY_RADIOSITYPROCESS_DONE " ) , TEXT ( " NOTIFY_LIGHTING_UNIT_DISPLAY_SYSTEM_CHANGE " ) , TEXT ( " NOTIFY_BEGIN_RENDERING_REFLECT_REFRACT_MAP " ) , TEXT ( " NOTIFY_BEGIN_RENDERING_ACTUAL_FRAME " ) , TEXT ( " NOTIFY_BEGIN_RENDERING_TONEMAPPING_IMAGE " ) , TEXT ( " NOTIFY_RADIOSITY_PLUGIN_CHANGED " ) , TEXT ( " NOTIFY_SCENE_UNDO " ) , TEXT ( " NOTIFY_SCENE_REDO " ) , TEXT ( " NOTIFY_MANIPULATE_MODE_OFF " ) , TEXT ( " NOTIFY_MANIPULATE_MODE_ON " ) , TEXT ( " NOTIFY_SCENE_XREF_PRE_MERGE " ) , TEXT ( " NOTIFY_SCENE_XREF_POST_MERGE " ) , TEXT ( " NOTIFY_OBJECT_XREF_PRE_MERGE " ) , TEXT ( " NOTIFY_OBJECT_XREF_POST_MERGE " ) , TEXT ( " NOTIFY_PRE_MIRROR_NODES " ) , TEXT ( " NOTIFY_POST_MIRROR_NODES " ) , TEXT ( " NOTIFY_NODE_CLONED " ) , TEXT ( " NOTIFY_PRE_NOTIFYDEPENDENTS " ) , TEXT ( " NOTIFY_POST_NOTIFYDEPENDENTS " ) , TEXT ( " NOTIFY_MTL_REFDELETED " ) , TEXT ( " NOTIFY_TIMERANGE_CHANGE " ) , TEXT ( " NOTIFY_PRE_MODIFIER_ADDED " ) , TEXT ( " NOTIFY_POST_MODIFIER_ADDED " ) , TEXT ( " NOTIFY_PRE_MODIFIER_DELETED " ) , TEXT ( " NOTIFY_POST_MODIFIER_DELETED " ) , TEXT ( " NOTIFY_FILELINK_POST_RELOAD_PRE_PRUNE " ) , TEXT ( " NOTIFY_PRE_NODES_CLONED " ) , TEXT ( " NOTIFY_POST_NODES_CLONED " ) , TEXT ( " NOTIFY_SYSTEM_PRE_DIR_CHANGE " ) , TEXT ( " NOTIFY_SYSTEM_POST_DIR_CHANGE " ) , TEXT ( " NOTIFY_SV_SELECTIONSET_CHANGED " ) , TEXT ( " NOTIFY_SV_DOUBLECLICK_GRAPHNODE " ) , TEXT ( " NOTIFY_PRE_RENDERER_CHANGE " ) , TEXT ( " NOTIFY_POST_RENDERER_CHANGE " ) , TEXT ( " NOTIFY_SV_PRE_LAYOUT_CHANGE " ) , TEXT ( " NOTIFY_SV_POST_LAYOUT_CHANGE " ) , TEXT ( " NOTIFY_BY_CATEGORY_DISPLAY_FILTER_CHANGED " ) , TEXT ( " NOTIFY_CUSTOM_DISPLAY_FILTER_CHANGED " ) , TEXT ( " NOTIFY_L
# if MAX_PRODUCT_YEAR_NUMBER >= 2018
, TEXT ( " NOTIFY_PRE_VIEWPORT_TOOLTIP " ) , TEXT ( " NOTIFY_WELCOMESCREEN_DONE " ) , TEXT ( " NOTIFY_PLAYBACK_START " ) , TEXT ( " NOTIFY_PLAYBACK_END " ) , TEXT ( " NOTIFY_SCENE_EXPLORER_NEEDS_UPDATE " ) , TEXT ( " NOTIFY_FILE_POST_OPEN_PROCESS_FINALIZED " ) , TEXT ( " NOTIFY_FILE_POST_MERGE_PROCESS_FINALIZED " )
# endif
2021-11-07 23:43:01 -05:00
# if MAX_PRODUCT_YEAR_NUMBER >= 2022
, TEXT ( " NOTIFY_PRE_PROJECT_FOLDER_CHANGE " ) , TEXT ( " NOTIFY_POST_PROJECT_FOLDER_CHANGE " ) , TEXT ( " NOTIFY_PRE_MXS_STARTUP_SCRIPT_LOAD " ) , TEXT ( " NOTIFY_ACTIVESHADE_IN_VIEWPORT_TOGGLED " ) , TEXT ( " NOTIFY_SYSTEM_SHUTDOWN_CHECK " ) , TEXT ( " NOTIFY_SYSTEM_SHUTDOWN_CHECK_FAILED " ) , TEXT ( " NOTIFY_SYSTEM_SHUTDOWN_CHECK_PASSED " ) , TEXT ( " NOTIFY_FILE_POST_MERGE3 " ) , TEXT ( " NOTIFY_ACTIVESHADE_IN_FRAMEBUFFER_TOGGLED " ) , TEXT ( " NOTIFY_PRE_ACTIVESHADE_IN_VIEWPORT_TOGGLED " ) , TEXT ( " NOTIFY_POST_ACTIVESHADE_IN_VIEWPORT_TOGGLED " )
# endif
, TEXT ( " NOTIFY_INTERNAL_USE_START " ) } ;
# pragma warning(pop)
int i = 0 ;
for ( int Code : Codes )
{
RegisterNotification ( On3dsMaxNotification , this , Code ) ;
NotificationCodetoString . Add ( Code , Strings [ i ] ) ;
2021-11-25 12:45:05 -05:00
NotificationCodesRegistered . Add ( Code ) ;
2021-11-07 23:43:01 -05:00
+ + i ;
}
2021-12-06 14:48:33 -05:00
}
void FNotifications : : StartSceneChangeTracking ( )
{
if ( bSceneChangeTracking )
{
return ;
}
bSceneChangeTracking = true ;
2021-11-07 23:43:01 -05:00
NodeEventCallback = MakeUnique < FNodeEventCallback > ( Exporter . GetSceneTracker ( ) ) ;
// Setup Node Event System callback
// https://help.autodesk.com/view/3DSMAX/2018/ENU/?guid=__files_GUID_7C91D285_5683_4606_9F7C_B8D3A7CA508B_htm
NodeEventCallback - > CallbackKey = GetISceneEventManager ( ) - > RegisterCallback ( NodeEventCallback . Get ( ) ) ;
2021-12-06 14:48:33 -05:00
}
2021-11-25 12:45:05 -05:00
2021-12-06 14:48:33 -05:00
void FNotifications : : StopSceneChangeTracking ( )
{
if ( ! bSceneChangeTracking )
{
return ;
}
bSceneChangeTracking = false ;
GetISceneEventManager ( ) - > UnRegisterCallback ( NodeEventCallback - > CallbackKey ) ;
NodeEventCallback . Reset ( ) ;
NodeObserver - > Reset ( ) ;
MaterialObserver - > Reset ( ) ;
2021-11-07 23:43:01 -05:00
}
FString FNotifications : : ConvertNotificationCodeToString ( int code )
{
FString * Str = NotificationCodetoString . Find ( code ) ;
return Str ? * Str : TEXT ( " <unknown> " ) ;
}
void FNotifications : : On3dsMaxNotification ( void * param , NotifyInfo * info )
{
2021-12-06 14:48:33 -05:00
FNotifications & NotificationsHandler = * static_cast < FNotifications * > ( param ) ;
2021-11-07 23:43:01 -05:00
IExporter * Exporter = & NotificationsHandler . Exporter ;
switch ( info - > intcode )
{
2021-12-06 14:48:33 -05:00
// Skip some events to display(spamming tests)
2021-11-07 23:43:01 -05:00
case NOTIFY_VIEWPORT_CHANGE :
case NOTIFY_PRE_RENDERER_CHANGE :
case NOTIFY_POST_RENDERER_CHANGE :
case NOTIFY_CUSTOM_ATTRIBUTES_ADDED :
case NOTIFY_CUSTOM_ATTRIBUTES_REMOVED :
case NOTIFY_MTL_REFDELETED :
break ;
// This one crashes when calling LogInfo
case NOTIFY_PLUGINS_PRE_SHUTDOWN :
Exporter - > Shutdown ( ) ;
break ;
default :
LOG_DEBUG_HEAVY ( FString ( TEXT ( " Notify: " ) ) + NotificationsHandler . ConvertNotificationCodeToString ( info - > intcode ) ) ;
} ;
2021-12-06 14:48:33 -05:00
if ( NotificationsHandler . bSceneChangeTracking )
{
ISceneTracker & SceneTracker = Exporter - > GetSceneTracker ( ) ;
switch ( info - > intcode )
{
case NOTIFY_NODE_POST_MTL :
// Event - node got a new material
break ;
2021-11-07 23:43:01 -05:00
2021-12-06 14:48:33 -05:00
case NOTIFY_SCENE_ADDED_NODE :
{
// note: INodeEventCallback::Added/Deleted is not used because there's a test case when it fails:
// When a box is being created(dragging corners using mouse interface) and then cancelled during creation(RMB pressed)
// INodeEventCallback::Deleted event is not fired by Max, although Added was called(along with other change events during creation)
INode * Node = reinterpret_cast < INode * > ( info - > callParam ) ;
LogDebugNode ( NotificationsHandler . ConvertNotificationCodeToString ( info - > intcode ) , Node ) ;
SceneTracker . NodeAdded ( Node ) ;
break ;
}
case NOTIFY_SCENE_PRE_DELETED_NODE :
{
// note: INodeEventCallback::Deleted is not called when object creation was cancelled in the process
INode * Node = reinterpret_cast < INode * > ( info - > callParam ) ;
LogDebugNode ( NotificationsHandler . ConvertNotificationCodeToString ( info - > intcode ) , Node ) ;
SceneTracker . NodeDeleted ( reinterpret_cast < INode * > ( info - > callParam ) ) ;
break ;
}
}
}
// Handle events not related to tracking scene changes
2021-11-07 23:43:01 -05:00
switch ( info - > intcode )
{
2021-11-25 12:45:05 -05:00
// Handle New/Reset events - reset tracking immediately when "Pre events are received - after this point all nodes are invalid, don't wait for "Post" event
case NOTIFY_SYSTEM_PRE_NEW : // Sent when File>New>New All is selected
case NOTIFY_SYSTEM_PRE_RESET : // Sent when Reset OR File>New>New From Template is selected
2021-11-07 23:43:01 -05:00
Exporter - > Reset ( ) ;
break ;
case NOTIFY_FILE_POST_OPEN :
Exporter - > Reset ( ) ;
break ;
}
}
}
# include "Windows/HideWindowsPlatformTypes.h"
# endif // NEW_DIRECTLINK_PLUGIN