Useful mxs sdk extension functions

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

REPLY TO THREAD
 
Thread Tools Search this Thread Display Modes
  02 February 2013
Originally Posted by Klunk: you could use this sort of thing instead of adding the edit normals mod but after converting to editable poly...

if not hasSpecifiedNormals obj then 
      	buildSpecifiedNormals obj;	
    


let me know any strangeness, they seem to be a bit "odd" sometimes but using the reset seems correct any issues (not an issue for my purpose as I'm setting them procedurally most of the time).

my global idea is to write PolySkin... the max skin is not optimized at all. it looks like people who wrote it never expected that it would be used in real time. i've made some tests... my expectation - the skin can be at least five times faster...
 
  02 February 2013
working with BitArray i found that shift bitArray function might be very useful in MXS:

    def_visible_primitive(shift,"shiftBitArray");
Value* shift_cf(Value **arg_list, int count)
{
	check_arg_count_with_keys(shift, 2, count);
	type_check(arg_list[1],Integer,"second argument");						//negative shifts left, positive shifts right 

	int start = key_arg_or_default(start,Integer::intern(1))->to_int() - 1;	//start index for shift. 1 based
	bool size = (key_arg_or_default(size,&false_value) == &true_value);		//do resize after shift. bool

	if (is_bitarray(arg_list[0]))
	{
		BitArray b = arg_list[0]->to_bitarray();
		int count = arg_list[1]->to_int();
		int dir = (count > 0) ? RIGHT_BITSHIFT : LEFT_BITSHIFT;
		count = abs(count);
		
		if (dir == LEFT_BITSHIFT) 
		{
			b.Shift(dir, count, start);
			if (size) b.SetSize(b.GetSize() - count, 1);
			else for (int i = 0, s = b.GetSize() - 1; i < count; i++) b.Set(s - i,false);
		}
		else
		{
			if (size) b.SetSize(b.GetSize() + count, 1);
			b.Shift(dir, count, start);
			for (int i = start, k = 0; i < b.GetSize(), k < count; i++, k++) b.Set(i,false);
		}
		return new BitArrayValue(b);
	}
	return &undefined;
}
    

it works different than the SDK method. after shift it clears left/right bits. which makes more sense for me.

Last edited by denisT : 02 February 2013 at 04:43 PM.
 
  02 February 2013
these are pretty slick

had call to use the cubic ease In out for something I'm working on, 6-7 time faster than the mxs version. t is time or x, b = start value, c = end value - start value and d = duration.

Cubic Ease In Out
<float> easeInOutCubic <float t> <float b> <float c> <float d>

def_visible_primitive(easeInOutCubic, "easeInOutCubic");
 
 Value* easeInOutCubic_cf(Value **arg_list, int count)
 {
 	check_arg_count(easeInOutCubic, 4, count);
 	float t = arg_list[0]->to_float();
 	float b = arg_list[1]->to_float();
 	float c = arg_list[2]->to_float();
 	float d = arg_list[3]->to_float();
 
 	if((t/=d/2) < 1.0) return Float::intern(c/2*t*t*t + b);
 	return Float::intern(c/2*((t-=2)*t*t + 2) + b);	
 }


glad no-one spotted the deliberate mistake

Last edited by Klunk : 02 February 2013 at 08:33 AM.
 
  02 February 2013
something i needed to speed up custom mesh in scripted plugins, also tidies up the code a lot to, compress the get/set edge visibility for a face to a single call...

<bitarray> getEdgeVisFlags <editable_mesh> <face>

def_visible_primitive(getEdgeVisFlags,"getEdgeVisFlags");
  
  Value* getEdgeVisFlags_cf(Value **arg_list, int count)
  {
  	check_arg_count_with_keys(getEdgeVisFlags, 2, count);
  
  	Mesh* pmesh = get_meshForValue(arg_list[0], MESH_READ_ACCESS, NULL, getEdgeVisFlags);
  
  	int face = arg_list[1]->to_int() - 1; // mxs to sdk
  	range_check(face,0,(pmesh->numFaces - 1), GetString(IDS_FACE_INDEX_OUT_OF_RANGE));
  
  	BitArray viz(3);
  	viz.ClearAll();
  
  	for(int i = 0; i < 3; i++) 
  		if(pmesh->faces[face].getEdgeVis(i))
  			viz.Set(i);
  	
  	return new BitArrayValue(viz);
  }


setEdgeVisFlags <editable_mesh> <face> <bitarray>

def_visible_primitive(setEdgeVisFlags,"setEdgeVisFlags");
  
  Value* setEdgeVisFlags_cf(Value **arg_list, int count)
  {
  	check_arg_count_with_keys(setEdgeVisFlags, 3, count);
  
  	Mesh* pmesh = get_meshForValue(arg_list[0], MESH_WRITE_ACCESS, NULL, setEdgeVisFlags);
  
  	int face = arg_list[1]->to_int() - 1; // mxs to sdk
  	range_check(face,0,(pmesh->numFaces - 1), GetString(IDS_FACE_INDEX_OUT_OF_RANGE));
  
  	BitArray viz = arg_list[2]->to_bitarray();
  	viz.SetSize(3,1); // set to correct size regardless
  
  
  	pmesh->faces[face].setEdgeVisFlags(viz[0],viz[1],viz[2]);
  	return &ok;
  }

Last edited by Klunk : 02 February 2013 at 02:10 PM.
 
  02 February 2013
Originally Posted by denisT: my global idea is to write PolySkin... the max skin is not optimized at all. it looks like people who wrote it never expected that it would be used in real time. i've made some tests... my expectation - the skin can be at least five times faster...

i was right ... i can calculate skin deformation ~15 times faster than the skin modifier does do... now i need to minimize the number of notifications to react to...
 
  02 February 2013
is there a way of doing skinning on the gpu ? getting max to pass the bone transforms & vertex weighting to shaders would be nice.
 
  02 February 2013
these three functions draw dotted rectangle, circle, and polyline:

//--------------------------------------- Viewport Draw Dotted -------------------------------------//
#include "winutil.h"

def_visible_primitive(XORDottedRect, "drawDottedRect");
Value* XORDottedRect_cf(Value **arg_list, int count)
{
	check_arg_count_with_keys(XORDottedRect, 2, count);
	ViewExp* veiw = MAXScript_interface->GetActiveViewport();

	if (veiw && is_point2(arg_list[0]) && is_point2(arg_list[1]))
	{
		Point2 p0 = arg_list[0]->to_point2();
		Point2 p1 = arg_list[1]->to_point2();

		bool solid = key_arg_or_default(constant, Integer::intern(0))->to_int();
		bool erase = (key_arg_or_default(clear, &false_value) == &true_value);
		bool delayed = (key_arg_or_default(delayed, &false_value) == &true_value);

		XORDottedRect(veiw->GetHWnd(), IPoint2(p0.x, p0.y), IPoint2(p1.x, p1.y), solid, erase, delayed);
		return &true_value;
	}
	return &false_value;
}

def_visible_primitive(XORDottedCircle, "drawDottedCircle");
Value* XORDottedCircle_cf(Value **arg_list, int count)
{
	check_arg_count_with_keys(XORDottedCircle, 2, count);
	ViewExp* veiw = MAXScript_interface->GetActiveViewport();

	if (veiw && is_point2(arg_list[0]) && is_point2(arg_list[1]))
	{
		Point2 p0 = arg_list[0]->to_point2();
		Point2 p1 = arg_list[1]->to_point2();

		int solid = key_arg_or_default(constant, Integer::intern(0))->to_int();
		bool erase = (key_arg_or_default(clear, &false_value) == &true_value);
		bool delayed = (key_arg_or_default(delayed, &false_value) == &true_value);

		XORDottedCircle(veiw->GetHWnd(), IPoint2(p0.x, p0.y), IPoint2(p1.x, p1.y), solid, erase, delayed);
		return &true_value;
	}
	return &false_value;
}

def_visible_primitive(XORDottedPolyline, "drawDottedPolyline");
Value* XORDottedPolyline_cf(Value **arg_list, int count)
{
	check_arg_count_with_keys(XORDottedPolyline, 1, count);
	ViewExp* veiw = MAXScript_interface->GetActiveViewport();

	if (veiw && is_array(arg_list[0]))
	{
		bool closed = (key_arg_or_default(closed, &false_value) == &true_value);

		Array* points = (Array*)arg_list[0]; 
		if (closed) points->append(points->data[0]);

		int count = points->size;

		IPoint2* pp = new IPoint2[count];
		Point2 p;
		for (int i = 0; i < count; i++) 
		{
			p = points->data[i]->to_point2();
			pp[i] = IPoint2(p.x, p.y);
		}

		int solid = key_arg_or_default(constant, Integer::intern(0))->to_int();
		bool erase = (key_arg_or_default(clear, &false_value) == &true_value);
		bool delayed = (key_arg_or_default(delayed, &false_value) == &true_value);

		XORDottedPolyline(veiw->GetHWnd(), count, pp, solid, erase, delayed);
		return &true_value;
	}
	return &false_value;
}


they have optional parameters... you can find their meanings in SDK documentation.
#constant (or solid) option works only for rectangle. for circle and polyline it seams like broken. i've supported it just in case of max will fix it later.
 
  02 February 2013
Klunk,
what do you think might be the best way to update PolyObject after its MNMesh was modified?
 
  02 February 2013
funny you should ask that.... I'm not really sure it's all a bit confusing :(
I was looking at the options with updating after copying map channels. defaultmapfaces (and other map channel polyop functions) uses this construct

 	EPoly* epi = NULL;
 	if (owner) {
 		epi = (EPoly*)((Animatable*)owner)->GetInterface(EPOLY_INTERFACE);
 	}
 
 	if (epi) 
 		epi->LocalDataChanged ((channel<1) ? PART_VERTCOLOR : PART_TEXMAP);
 	return &ok;
 


which seems to have no effect when using defaultmapfaces btw.... (also update in mxs doesn't always work either)

UpdateDisplayVertexColors & SetDisplayVertexColors have not effect in this case either.

for generic mesh changes you could try InvalidateGeomCache() maybe.
 
  02 February 2013
Originally Posted by Klunk: funny you should ask that.... I'm not really sure it's all a bit confusing :(
I was looking at the options with updating after copying map channels. defaultmapfaces (and other map channel polyop functions) uses this construct

  	EPoly* epi = NULL;
  	if (owner) {
  		epi = (EPoly*)((Animatable*)owner)->GetInterface(EPOLY_INTERFACE);
  	}
  
  	if (epi) 
  		epi->LocalDataChanged ((channel<1) ? PART_VERTCOLOR : PART_TEXMAP);
  	return &ok;
  


which seems to have no effect when using defaultmapfaces btw.... (also update in mxs doesn't always work either)

UpdateDisplayVertexColors & SetDisplayVertexColors have not effect in this case either.

for generic mesh changes you could try InvalidateGeomCache() maybe.


i've tried almost everyting... and couldn't update anyway. maxscript UPDATE works fine, but i want to have complete deform function. i've tried to send notification messages... no luck. but i'm 100% sure it's very easy i just don't know what update and where to send
 
  02 February 2013
that's what i do and it makes sense for me, but... doesn't work:

bool updatePolyObject(INode* node)
{
	Object* obj = Get_Object_Or_XRef_BaseObject(node->GetObjectRef());
	BaseInterface* ip;	
	if ((ip = ((Animatable*)obj)->GetInterface(EPOLY_INTERFACE)) == NULL)
	{
		EPoly* ep = (EPoly*)ip;
		ep->LocalDataChanged(PART_GEOM);
		obj->NotifyDependents(FOREVER,PART_GEOM,REFMSG_CHANGE,N  OTIFY_ALL,TRUE);
		ep->RefreshScreen();
		return true;
	}
	return false;
}
 
  02 February 2013
but if i call notifydependents node partid:#geo with mxs after my sdk update it immediately updates the poly and redraws views
 
  02 February 2013
Originally Posted by denisT: that's what i do and it makes sense for me, but... doesn't work

I think you may have a typo in there, you probably meant to say != NULL instead of == NULL.

Martijn
 
  02 February 2013
Originally Posted by magicm: I think you may have a typo in there, you probably meant to say != NULL instead of == NULL.

oops... maybe i really have == NULL. and my function works? thanks...
 
  02 February 2013
Originally Posted by denisT: oops... maybe i really have == NULL. and my function works? thanks...

another puzzle...
update works as:

bool updatePolyObject(INode* node)
{
	Object* obj = Get_Object_Or_XRef_BaseObject(node->GetObjectRef());
	BaseInterface* ip;	
	if ((ip = ((Animatable*)obj)->GetInterface(EPOLY_INTERFACE)) != NULL)
	{
		EPoly* ep = (EPoly*)ip;
		//ep->LocalDataChanged(PART_GEOM);
		obj->NotifyDependents(FOREVER,PART_GEOM,REFMSG_CHANGE);  
		return true;
	}
	return false;
}


but it's slower than call (update node) with mxs... LocalDataChanged is slower than NotifyDependents(FOREVER,PART_GEOM,REFMSG_CHANGE). what am i missing? what can mxs update do to make update faster?
 
reply share thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
CGSociety
Society of Digital Artists
www.cgsociety.org

Powered by vBulletin
Copyright 2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump
Miscellaneous

All times are GMT. The time now is 04:21 PM.


Powered by vBulletin
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.