Notifications
Clear all

[Closed] Useful mxs sdk extension functions

random function of the week

this is my version about the same matter:

def_visible_primitive(rescaleMatrix, "rescaleMatrix");
Value* rescaleMatrix_cf(Value** arg_list, int count)
{
	check_arg_count_with_keys(rescaleMatrix, 1, count);
	Matrix3 tm = arg_list[0]->to_matrix3();
	BOOL reset = key_arg_or_default(reset, &false_value)->to_bool();
	if (reset) tm.Orthogonalize();
	tm.NoScale();
	if (is_point3(key_arg(scale)))
	{
		Point3 scl = key_arg(scale)->to_point3();
		tm.PreScale(scl);
	}
	else
	{
		
	}
	return new Matrix3Value(tm);
}

don’t worry about empty ‘else’. the scale key argument might be not just a point3 value in my case

also it might be ‘in-place’ function to save memory on mxsvalue return

this thread is a bomb. thanks guys!
wonder what had happen to code blocks that Klvnk had posted over the 2015 year… seems like the description is in place but code is missing.

I have a cpp function exposed to maxscript via def_visible_primitive and it leaks memory only if used in a loop (it doesn’t leak at all if I call it hundred times outside the loop).
upd
Ok. Solved. It was a AColor that I had to explicitly assign nullptr in order it to stop leak.

discovered something new to me today… shapes have an internal hierarchy (which I don’t think is exposed to mxs… so here it is

// GetChildCurves <shape> <curve>

def_visible_primitive(GetChildCurves, "GetChildCurves");

Value* GetChildCurves_cf(Value **arg_list, int count)
{
	check_arg_count(GetChildCurves, 2, count);

	MAXNode* shape = (MAXNode*)arg_list[0];
	INode* node = get_valid_node(shape, GetChildCurves);
	Object* obj = node->GetObjectRef();

	if (obj->SuperClassID() == GEN_DERIVOB_CLASS_ID)
		obj = ((IDerivedObject*)obj)->FindBaseObject();

	if(obj->ClassID() != splineShapeClassID && obj->ClassID() != Class_ID(SPLINE3D_CLASS_ID,0))
		throw RuntimeError (GetString(IDS_SHAPE_OPERATION_ON_NONSPLINESHAPE), obj->GetObjectName()); 

	SplineShape* spline = dynamic_cast<SplineShape*>(obj);

	int curve = arg_list[1]->to_int() - 1; // mxs to sdk
	range_check(curve, 0,spline->shape.splineCount - 1, GetString(IDS_SHAPE_SPLINE_INDEX_OUT_OF_RANGE));

	GenericHierarchy& hierarchy = spline->OrganizeCurves(MAXScript_time()).hier;

	int number_of_children = hierarchy.NumberOfChildren(curve);
	if(!number_of_children) return &undefined;

	one_typed_value_local(Array* result);
	vl.result = new Array(number_of_children);

	for(int i = 0; i < number_of_children; ++i)
		vl.result->append(Integer::intern(hierarchy.GetChild(curve, i) + 1));

	return_value(vl.result);
}


// GetCurvesParent <shape> <curve>

def_visible_primitive(GetCurvesParent, "GetCurvesParent");

Value* GetCurvesParent_cf(Value **arg_list, int count)
{
	check_arg_count(GetCurvesParent, 2, count);

	MAXNode* shape = (MAXNode*)arg_list[0];
	INode* node = get_valid_node(shape, GetCurvesParent);
	Object* obj = node->GetObjectRef();

	if (obj->SuperClassID() == GEN_DERIVOB_CLASS_ID)
		obj = ((IDerivedObject*)obj)->FindBaseObject();

	if(obj->ClassID() != splineShapeClassID && obj->ClassID() != Class_ID(SPLINE3D_CLASS_ID,0))
		throw RuntimeError (GetString(IDS_SHAPE_OPERATION_ON_NONSPLINESHAPE), obj->GetObjectName()); 

	SplineShape* spline = dynamic_cast<SplineShape*>(obj);

	int curve = arg_list[1]->to_int() - 1; // mxs to sdk
	range_check(curve, 0,spline->shape.splineCount - 1, GetString(IDS_SHAPE_SPLINE_INDEX_OUT_OF_RANGE));

	GenericHierarchy& hierarchy = spline->OrganizeCurves(MAXScript_time()).hier;

	HierarchyEntry* curve_hentry = hierarchy.FindEntry(curve);
	return curve_hentry->parent ? Integer::intern(curve_hentry->parent->data + 1) : &undefined;
}

so it see it working create some text say an 8 for example convert to a spline and the function returns the curve indices of the two inner curves if supplied the out curve index

interesting… i don’t know how to use it yet but definitely add to my mxs extension. Thanks!

it does some kind of on the fly analysis (organisecurves function)… if a curve is entirely enclosed by another curve it’s considered it’s child.

this can be useful, for example, for sorting “caps” and “holes”. I met a similar problem some time in the past. maybe I have to review that project.

looking at the text prim they cache their hierarchy so not to call OrganizeCurves if they don’t have to so it maybe best to rewrite the above code to dump the whole hierarchy in one go as an array of arrays

like this for example…

 def_visible_primitive(GetShapeHeirarchy, "GetShapeHeirarchy");

Value* GetShapeHeirarchy_cf(Value** arg_list, int count)
{
	check_arg_count (GetShapeHeirarchy, 1, count);
	
	INode* node = arg_list[0]->to_node();
	ObjectState os = node->EvalWorldState(MAXScript_time());
	Object* refobj = os.obj;

	if(refobj->SuperClassID() == SHAPE_CLASS_ID)
	{
		ShapeObject* shape = static_cast<ShapeObject *>(refobj);

		GenericHierarchy& hierarchy = shape->OrganizeCurves(MAXScript_time()).hier;
		int num_curves = shape->NumberOfCurves();

		one_typed_value_local(Array* result);
		vl.result = new Array(num_curves);

		for(int curve = 0; curve < num_curves; ++curve)
		{
			int number_of_children = hierarchy.NumberOfChildren(curve);
			if(number_of_children == 0)
				vl.result->append(&undefined);	
			else
			{
				Array* children = new Array(number_of_children);
				for(int i = 0; i < number_of_children; ++i)
					children->append(Integer::intern(hierarchy.GetChild(curve, i) + 1));
				vl.result->append(children);
			}
		}
		return_value (vl.result); 
	}
	return &undefined;
}

text with the string ABC produces the result…

#(#(2), undefined, #(4, 5), undefined, undefined, undefined)

if you outline a donut shape you get the following…

#(#(3), #(4), #(2), undefined)

Page 17 / 18