Notifications
Clear all

[Closed] Useful mxs sdk extension functions

return a unique array of all assigned materials

uses the max stl allocator found previously on this thread though should be pretty easy to port to Tabs. Really wish cgsoc would fix the code formating as it’s next to useless as is :argh:

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

i’m not sure that it will be dramatically faster or memory safer than mxs:

(
	delete objects
	for k=1 to 10000 do (box material:(standard()))
	gc()
	(
		t1 = timestamp()
		m1 = heapfree
		done = #{}
		mats = for node in objects where node.mat != undefined and not done[h = getHandleByAnim node.mat] collect 
		(
			append done h
			node.mat
		)
		format "nodes:% mats:% time:% memory:%
" objects.count mats.count (timestamp() - t1) (m1 - heapfree)
	)
)
-- nodes:10000 mats:10000 time:509 memory:256L

Nice one Klunk, it’s stuff like this that will stop me asking too many questions

i get
mxs
nodes:1000 mats:1000 time:79 memory:157260L

sdk
nodes:1000 mats:1000 time:2 memory:108L

seems pretty conclusive

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

it’s fast. but do we really need it so fast ;)?

improves it by 2
mxs nodes:1000 mats:1000 time:39 memory:157260L
still 20x slower

every little bit helps, though it’s not all about speed I like to keep functions in an mxs dlx easy to maintain and debug… keeps your mxs really really clean & tidy too with the added benefit of coloured function names so it looks all pretty

sometimes it’s the best point for me too

typedef std::vector< Mtl*, MaxAlloc <Mtl*> > mtlvector;
typedef mtlvector::iterator mtlvector_it;
  
  void EnumerateNodeTree(INode* node, mtlvector& mats, MAXClass* mxc = NULL)
  {
  	Mtl* mat = node->GetMtl();

	if(mat)
	{
		if (mxc != NULL)
		{
			Class_ID cid = mat->ClassID();
			SClass_ID sid = mat->SuperClassID();
			MAXClass* cls = lookup_MAXClass(&cid, sid);
			if (cls == mxc) mats.push_back(mat);
		}
		else mats.push_back(mat);
	}
  
  	for(int i = 0; i < node->NumberOfChildren(); ++i) EnumerateNodeTree(node->GetChildNode(i), mats, mxc);
  }
  
def_visible_primitive(getAssignedMaterials, "getAssignedMaterials");
  
bool mtlcomparefn(Mtl* a, Mtl* b) { return (Animatable::GetHandleByAnim(a) <  Animatable::GetHandleByAnim(b)); }
bool mtlequalfn(Mtl* a, Mtl* b) { return (Animatable::GetHandleByAnim(a) ==  Animatable::GetHandleByAnim(b)); }
  
Value* getAssignedMaterials_cf(Value** arg_list, int count)
{
 	INode* node;
	if (count_with_keys() == 0)
	{
		node = MAXScript_interface->GetRootNode();
	}
	else 
	{
		check_arg_count_with_keys(getAssignedMaterials, 1, count);
		if (is_node(arg_list[0]))
		{
			node = arg_list[0]->to_node();
		}
		else if (is_rootnode(arg_list[0]))
		{
			node = arg_list[0]->to_rootnode();
		}
	}
	if (node)
	{
		MAXClass* mxc = NULL;		
		if (key_arg(class)->is_kind_of(class_tag(MAXClass)))
		{
			mxc = (MAXClass*)key_arg(class);
		}

  		mtlvector assigned;
  
  		EnumerateNodeTree(node, assigned, mxc);
  		//std::sort(assigned.begin(), assigned.end(), mtlcomparefn);
  		mtlvector_it last = std::unique(assigned.begin(), assigned.end(), mtlequalfn);
  	
  		Array* mtls = new Array(0);
  		for(mtlvector_it it = assigned.begin(); it != last; ++it) mtls->append(MAXClass::make_wrapper_for(*it));
  
  		return mtls; 
	}
	return &undefined;
}

there is a modified version of Klvnk’s function shown above.
it can optionally take an argument with a specified node or rootnode to search in all its children, and it takes an extra argument where you can specify a searching class. only this class materials will go to the list.

possible example of using:

getAssignedMaterials (xrefs.getXRefFile 1).tree class:blend

in a similar fashion, all animated leaf controllers

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

very nice!

there is my suggestion:

inline bool isControl(Animatable* anim) 
{ 
	return (GetControlInterface(anim) ? 1 : 0);
}

it’s a little safer method

so enum proc could be:

	bool proc(Animatable *anim)
	{
		if (anim->IsAnimated())
		{	
			Control* ctrl = GetControlInterface(anim);
			if (ctrl && ctrl->IsKeyable() && ctrl->IsLeaf()) ctrls.push_back(ctrl);
		}
		return true;
	}

thanks denis

though probably not best to use it though :shrug: as “anims” seem to hang around even after a reset or the node they are attached to has long been deleted !

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

sometimes it’s not bad.
if you combine it with DependentEnumProc you can find lost controllers (with no dependents)

Simple turn off, turn on, and delete modifiers


void ChangeModFromNode(INode* node, BOOL Enable, BOOL Delete){
	if (! node)return;

	Object *obj = node->GetObjectRef();
	IDerivedObject *D_obj = NULL;

	if (obj->SuperClassID() == GEN_DERIVOB_CLASS_ID){
		D_obj = static_cast<IDerivedObject *> (obj);
	}
	else{
		D_obj = CreateDerivedObject();
		D_obj->TransferReferences(obj);
		D_obj->ReferenceObject(obj);
	}
	const int NumMods = D_obj->NumModifiers();
	for(int i = 0; i < NumMods; i++){
		if (Delete == TRUE){
			D_obj->DeleteModifier(0);
		}
		else{
			Modifier *tMod = D_obj->GetModifier(i);
			if (Enable == FALSE){
				tMod->DisableMod();
			}
			else{
				tMod->EnableMod();
			}
		}
	}
}


void ChangeModTest(){
	ip = GetCOREInterface();
	t = GetCOREInterface()->GetTime();
	for (int i=0; i < ip->GetSelNodeCount(); i++){
		INode *node = ip->GetSelNode(i);
		ChangeModFromNode(node, FALSE, FALSE);  // TURN OFF
		//ChangeModFromNode(node, TRUE, FALSE);  // TURN ON
		//ChangeModFromNode(node, FALSE, TRUE);  // DELETE ALL
	}
	ip->FlushUndoBuffer();
	ip->RedrawViews(ip->GetTime());
}




1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

it’s already simple in mxs, and hard to make it easier:

<node>.modifiers.enabled = off
Page 14 / 18