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:
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
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
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
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 !
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());
}
it’s already simple in mxs, and hard to make it easier:
<node>.modifiers.enabled = off