Notifications
Clear all

[Closed] SDK how return struct to maxscript?

I’m trying the sdk for the first time, as a learning experience i’m porting certain functions to the sdk as function publishing.
I have successfully been able to port a function and return a Point3 position from it.
Now i want to port another functions. but i require to return more then one parameter type. Is there a way to return a struct in which i have for example and array of points, a few int values and a boolean?

I have been looking at the samples to see if i can find something similar but i haven’t found anything.

i was looking at several examples that use four_value_locals or five_typed_value_locals_tls …
But i’m not sure if that’s the way to do it.

Anyone has any tips?

Thanks
Guillermo Leal

22 Replies

Guess you can pass variables by reference and assign them directly without the need to return anything.

def_visible_primitive(AssignByRef, "AssignByRef");
Value* AssignByRef_cf(Value** arg_list, int count)
{
	check_arg_count_with_keys(AssignByRef, 3, count);

	Thunk *var1 = arg_list[0]->to_thunk();
	Thunk *var2 = arg_list[1]->to_thunk();
	Thunk *var3 = arg_list[2]->to_thunk();

	var1->assign(new String(_T("Victory!!!")));
	var2->assign(new Point3Value(1, 2, 3));
	var3->assign(new BitArrayValue(666));


	return &true_value;

}

Then in mxs

AssignByRef &a &b &c
a
b
c.count

– true
– “Victory!!!”
– [1,2,3]
– 666

you could probably create and return one but I don’t think mxs would “understand” what it was getting. the generally accepted method is to return an array of values which in turn can be arrays or point3values etc here my implementation of polyop.intersectrayex as an example

def_struct_primitive(polyop_intersectRayEx, polyop, "intersectRayEx");

Value* polyop_intersectRayEx_cf(Value** arg_list, int count)
{
	check_arg_count(intersectRayEx, 2, count);
	MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_READ_ACCESS, NULL, intersectRayEx);
	Ray ray = arg_list[1]->to_ray();

// get the node transforms

	INode* node = get_valid_node(arg_list[0], intersectRayEx);
	Matrix3 tm  = node->GetObjectTM(MAXScript_time());
	Matrix3 itm = Inverse(tm);
	
// convert the ray in to local space

	Ray os_ray;
	os_ray.p   = itm * ray.p;
	os_ray.dir = VectorTransform(itm, ray.dir);
	
	float t;
	Point3 normal;
	int fi;
	Tab<float> bary; 
	if(!pmesh->IntersectRay(os_ray,t,normal,fi,bary))
		return &undefined;

// convert bary table into array value
	
	Array* barray = new Array(bary.Count());
	for(int i = 0; i < bary.Count(); ++i)
		barray->append(Float::intern(bary[i]));

// Return the array containing the intersection details 

	one_typed_value_local(Array* result);
	vl.result = new Array(3);
	vl.result->append(new RayValue((os_ray.p + os_ray.dir * t) * tm, Normalize(VectorTransform(tm, normal))));
	vl.result->append(Integer::intern (fi+1));
	vl.result->append(barray);
	return_value (vl.result); 
}

with the result looking something like in mxs
#((ray [-22.0326,43.1826,28.3888] [-0.617795,0.767651,-0.170415]), 6, #(0.212238, 0.0, 0.593346, 0.194416))

Thanks to both of you.

I end up doing something similar to what you just said, I created arrays inside arrays with all the information then in maxscript i convert them back to a struct. I just wasn’t sure it was the correct way. I was just doing it that way because i saw some samples written that way.

Another couple of questions about one_typed_value_local.

how does it work When i first saw that there were different defines one_typed_value_local, two_typed_value_local , three_typed_value_local, etc. I thought i could put all the values in there and then by returning the result it would bring everything into maxscript. but of course it didn’t work. Then what are they for?

Also whats the difference between one_typed_value_local and one_typed_value_local_tls that i see in lots of the sample code.

Thanks,
Guillermo

have a look at

Value*
get_max_file_asset_metadata_cf(Value** arg_list, int count)

in avg_DLX.cpp

looks like it returns an array of structs

Thanks Klvnk,

I still haven’t figure it out how to use that code, but i will keep looking into.

yep mxs at the source can be extremely arcane and obscure

Klvnk,

I have another completely different question.

in maxscript i have the following code to draw some viewport lines and points while the code is generating the positions.

fn DisplayDrawing =
	(

	local nodePoint

	gw.setTransform(Matrix3 1)
	
	for r = 1 to points.count do 
		(	
			if points[r].nodes.count  > 2 then 
				(
					thePoints = #()
					for n = 1 to points[r].nodes.count do
						(
							
							nodePoint = points[r].nodes[n].pos
							
							append thePoints nodePoint
								
							gw.setColor #line green
							gw.Polyline thePoints false  													

							gw.updateScreen()
							redrawViews() 		
						)

				)			
		)			
	)
	
	
fn doStuff =
(
	--- for loop generating the points
	for t = 1 to lots.count do
	(
		-- stuff here
		
		-- call the gw draw function
		DisplayDrawing()
	)
)

on chk_displayDrawing changed state do
(	
  unRegisterRedrawViewsCallback DisplayDrawing
  if state then
   registerRedrawViewsCallback DisplayDrawing
  completeRedraw()
)

I’m trying to do that on the sdk but i can’t find a solution.

The complete plugin is based on the FunctionPublishing sample in the howto solution.

I already have the function correctly generating a std::vector with all the positions i want to draw on the viewport.

but i can’t find how to implement it. I saw the post [SDK] issues drawing polyline in viewport
but i still can’t figure it out. I tried to use the code in the polycnt.cpp to register a callback but it didn’t work and crashed the plugin.
can you give me some guidelines? or perhaps you have done something similar in the past?

Thanks
Guillermo

have a look at the source for the function you are using in the script in the file

C:\Program Files\Autodesk\3ds Max **** SDK\maxsdk\samples\maxscript\mxsagni\GraphicsWindow.cpp

and go from there.

I will thanks,

Page 1 / 3