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
it is a bit of a catch all... maybe a selective pick of what you really need would help ? also InvalidateSurfaceUI call interacts with the editable poly UI which can't help.

void EditPolyObject::LocalDataChanged (DWORD parts) {
 	bool sel = (parts & PART_SELECT) ? TRUE : FALSE;
 	bool topo = (parts & PART_TOPO) ? TRUE : FALSE;
 	bool geom = (parts & PART_GEOM) ? TRUE : FALSE;
 	bool vertCol = (parts & PART_VERTCOLOR) ? true : false;
 	InvalidateTempData (parts);
 	if (topo||sel||vertCol) InvalidateSurfaceUI ();
 	if (topo) {
 		SynchContArray(mm.numv);
 		// We need to make sure our named selection sets' sizes match our sizes:
 		selSet[0].SetSize (mm.numv);
 		selSet[1].SetSize (mm.nume);
 		selSet[2].SetSize (mm.numf);
 		mm.InvalidateTopoCache( false );
 	}
 	if (geom||topo) {
 		MNNormalSpec *pNorm = mm.GetSpecifiedNormals();
 		if (pNorm)
 		{
 			// If we have specified normals, we need to clear flags to indicate that they need to be updated.
 			// If we have a PART_TOPO change, the nonspecified normals need to be rebuilt.
 			// If we have a PART_GEOM change, the nonexplicit normals need to be recomputed.
 			if (topo) pNorm->ClearFlag (MNNORMAL_NORMALS_BUILT);
 			else pNorm->ClearFlag (MNNORMAL_NORMALS_COMPUTED);
 		}
 
 		mm.InvalidateGeomCache ();
 		if (topo)
 			mm.freeRVerts ();
 	} else if (vertCol) mm.InvalidateHardwareMesh ();
 
 	if (sel) {
 		InvalidateNumberSelected ();
 		UpdateNamedSelDropDown ();
 	}
 	subdivValid.SetEmpty ();
 	if (killRefmsg.DistributeRefmsg())
 	NotifyDependents(FOREVER, parts, REFMSG_CHANGE);
 }


void EditPolyObject::InvalidateTempData (PartID parts) {
	if (!tempMove) {
		if (tempData) tempData->Invalidate (parts);
		if (parts & (PART_TOPO|PART_GEOM|PART_SELECT|PART_SUBSEL_TYPE)  )
		{
			//only invalidate the cache when it's actually being used.
			//invalidating the soft selection cache causes the subdivided mesh to be rebuilt if it's on
			int useSoftSel = 0;
			pblock->GetValue (ep_ss_use, GetCOREInterface()->GetTime(), useSoftSel, arValid);
			if ( useSoftSel )
			{
			InvalidateSoftSelectionCache ();
	}
		}
	}
	// we NEVER call InvalidateTopoCache, since that trashes the edge list.
	if (parts & PART_TOPO)
	{
		mm.ClearFlag(MN_MESH_PARTIALCACHEINVALID);
		mm.SetFlag(MN_CACHEINVALID);
		mm.freeRVerts();
	}
	if (parts & PART_GEOM) mm.InvalidateGeomCache ();
	if ((parts & PART_SELECT) && tempData) tempData->freeBevelInfo();


	// Any change in mesh should invalidate the preview.
	if (EpPreviewOn()) EpPreviewInvalidate ();
}

Last edited by Klunk : 02 February 2013 at 08:05 AM.
 
  04 April 2013
i have no idea why this useful function is not exposed for MXS:

def_visible_primitive (formatRenderTime, "formatRenderTime");
Value* formatRenderTime_cf(Value** arg_list, int count)
{
	check_arg_count_with_keys(all, 1, count);
	int time = arg_list[0]->to_int();
	BOOL hundredths = key_arg_or_default(all, &false_value)->to_bool();
	MSTR str;
	MAXScript_interface11->FormatRenderTime(time, str, hundredths);
	return new String(str);
}
 
  04 April 2013
i can't build this simple function:

def_visible_primitive(getControlHWND, "getControlHWND");
Value* getControlHWND_cf(Value **arg_list, int count)
{
	check_arg_count(getControlHWND, 1, count);
	if (is_rolloutcontrol(arg_list[0])) 
	{
		HWND hwnd = ((RolloutControl*)arg_list[0])->GetHWND();
		return IntegerPtr::intern((INT_PTR)hwnd);
	}
	return &undefined;
}

i have this error message:
error LNK2019: unresolved external symbol "public: struct HWND__ * __cdecl RolloutControl::GetHWND(void)" (?GetHWND@RolloutControl@@QEAAPEAUHWND__@@XZ) referenced in function "class Value * __cdecl getControlHWND_cf(class Value * *,int)"

as i understand the compiler can't find some lib file. but i have no idea which one missed. Any ideas?
thanks
 
  04 April 2013
don't think you can use that as it's not part of the "interface" e.g. it's not virtual... In the rolloutcontrols I've look at (mxsagni project in samples) and the one I attempted to implement the hwnd is defined in the child class with no imperative to implement a GetHWND() function.

though i maybe wrong and very often are the libraries are listed here

another edit doesn't link in one of my projects with a working custom rollout control so it should have all the necessary linkages.

Last edited by Klunk : 04 April 2013 at 08:45 AM.
 
  04 April 2013
Originally Posted by Klunk: don't think you can use that as it's not part of the "interface" e.g. it's not virtual... In the rolloutcontrols I've look at (mxsagni project in samples) and the one I attempted to implement the hwnd is defined in the child class with no imperative to implement a GetHWND() function.

this is from header "rollouts.h"

 visible_class (RolloutControl)
 
 class RolloutControl : public Value, public ReferenceMaker
 {
 public:
 	Value*		name;
 	Value*		caption;
 	Value*		init_caption;
 <...>
 
 	// added for r11
 	HWND GetHWND();
 };
 

it's public. it's visible... why is it not working?
 
  04 April 2013
i found a workaround:

def_visible_primitive(getControlHWND, "getControlHWND");
Value* getControlHWND_cf(Value **arg_list, int count)
{
	check_arg_count_with_keys(getControlHWND, 1, count);
	int id = key_arg_or_default(id,Integer::intern(0))->to_int();
	if (is_rolloutcontrol(arg_list[0])) 
	{
		RolloutControl *control = (RolloutControl*)arg_list[0];
		HWND hwnd = GetDlgItem(control->parent_rollout->page, control->control_ID + id);
		return IntegerPtr::intern((INT_PTR)hwnd);
	}
	return &undefined;
}

actually the new way is power powerful. using optional ID argument it can return HWND for a 'multi-controls' control (like a spinner)
 
  10 October 2013
Originally Posted by Klunk: I was hoping this would be more than a 2 man show Denis, if you don't already have these I think you will like them.....

exposes editable poly specified normals without using the edit normal modifier and having the target node selected and the modify panel open for it to work. It would be easy to expand on these if the functionality you need is not here, anyway enjoy....


def_visible_primitive(buildSpecifiedNormals,"buildSpecifiedNormals");
       
       Value* buildSpecifiedNormals_cf(Value **arg_list, int count)
       {
       	check_arg_count(buildSpecifiedNormals, 1, count);
       	MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, buildSpecifiedNormals);
       
       // clear any existing normals
       
       	if(pmesh->GetSpecifiedNormals())
       		pmesh->ClearSpecifiedNormals();
       
       // create an empty specified normals
       
       	pmesh->SpecifyNormals();
       	MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
       	if(nspec)
       	{
       // initialize the normals
       
       		nspec->Initialize();
       
       // create the faces
       
       		if(nspec->FAlloc(pmesh->numf))
       		{
       // build the normals
       
       			nspec->BuildNormals();
        
		     numfaces = nspec->GetNumFaces();        
			return Integer::intern(numfaces);
       		}
       	}
       	return &undefined;
       }



thanks, Klunk for this set of very useful functions... the only problem I have is to get MNMesh updated. as you see i've modifies the function above to return the number of nspec faces. the function returns 0 all the time, but the right number was allocated and built! what do we have to update the return the right number?

thanks
 
  10 October 2013
it's an odd one for sure....

if you call the getNumSpecNormalFaces function in mxs directly after the build function it returns the correct number of faces and that is using the same code !

nspec->GetNumFaces(); 


I've tried this changing this

if(nspec->FAlloc(pmesh->numf))


to

if(nspec->SetNumNormals(pmesh->numf))


makes no difference though may well be the proper way to do it though, but who can tell when the reference is so vague, never mind though we'll just plough on with python.


if you trust that max will always build the normals you can use

return Integer::intern(pmesh->numf);


it's not pretty or elegant or might not even be correct but maybe better than zero
 
  10 October 2013
Originally Posted by Klunk: it's an odd one for sure....

if you call the getNumSpecNormalFaces function in mxs directly after the build function it returns the correct number of faces and that is using the same code !

nspec->GetNumFaces(); 
 


Quote: I've tried this changing this

if(nspec->FAlloc(pmesh->numf))


to

if(nspec->SetNumNormals(pmesh->numf))


makes no difference though may well be the proper way to do it though, but who can tell when the reference is so vague, never mind though we'll just plough on with python.

i've tried to set number faces... it doesn't work either
Quote: if you trust that max will always build the normals you can use

return Integer::intern(pmesh->numf);


it's not pretty or elegant or might not even be correct but maybe better than zero

do i look like as a person who trusts max?

well... but i have an idea. there is a metod CheckNormals. it needs the Parent MNMesh to be set. so ...
nspec->SetParent(pmesh); nspec->CheckNormals();

it has to do all for us... and probably doesn't need any Allocation and Build. i don't have max right now to try. if you can try it, please, let me know how it works
 
  10 October 2013
sorry late night brain scramble should be using SetNumFaces not SetNumNormals

anyway this works for me

Value* buildSpecifiedNormals_cf(Value **arg_list, int count)
  {
  	check_arg_count(buildSpecifiedNormals, 1, count);
  	MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_WRITE_ACCESS, NULL, buildSpecifiedNormals);
  
  // clear any existing normals
  
  	if(pmesh->GetSpecifiedNormals())
  		pmesh->ClearSpecifiedNormals();
  
  // create an empty specified normals
  
  	pmesh->SpecifyNormals();
  	MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
  	if(nspec)
  	{
  // initialize the normals
  
  		nspec->Initialize();
  
  // create the faces
  
  		if(nspec->SetNumFaces(pmesh->numf))	
  		{
  // build the normals
  
  			nspec->BuildNormals();
 		    return Integer::intern(nspec->GetNumFaces());
  		}
  	}
      return &undefined;
  }

Last edited by Klunk : 10 October 2013 at 07:41 AM.
 
  10 October 2013
i've tried it... yes. it sets the number of faces, but it still doesn't update the nspec topology
 
  11 November 2013
getting the command panel rollup window hwnd, though possible via other means this is a more direct method

def_visible_primitive(getCommandPanelHWND, "getCommandPanelHWND");


Value* getCommandPanelHWND_cf(Value **arg_list, int count)
{
	check_arg_count(getCommandPanelHWND, 0, count);
	return IntegerPtr::intern((INT_PTR)MAXScript_interface->GetCommandPanelRollup()->GetHwnd());
}
 
  11 November 2013
by product of something else I was working on and I needed this info...

mxs usage

<array point3> getShapePolyLine <shape> <curve>

returns an array of points that make up the the drawn spline curve will take into account steps, optimize and adaptive.


def_visible_primitive(getShapePolyLine, "getShapePolyLine");

Value* getShapePolyLine_cf(Value **arg_list, int count)
{
	check_arg_count(getShapePolyLine, 2, count);

// handle the shape arg

	MAXNode* shape = (MAXNode*)arg_list[0];
	INode* node = get_valid_node(shape, getShapePolyLine);
	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());
	
// confident we have a shape object

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

// handle the curve index

	int index = arg_list[1]->to_int();
	if (index < 1 || index > spline->shape.splineCount)
		throw RuntimeError (GetString(IDS_SHAPE_SPLINE_INDEX_OUT_OF_RANGE), Integer::intern(index));

// grab the polyshape from our spline

	PolyShape pshape;
	spline->MakePolyShape(MAXScript_interface->GetTime(), pshape, PSHAPE_BUILTIN_STEPS, spline->shape.optimize);
	
// create an array from the curve we want

	PolyLine* pline  = &pshape.lines[index-1];
	int numPts = pline->numPts;
	one_typed_value_local(Array* result);

	vl.result = new Array(numPts);

	Point3 p;	
	for(int i = 0; i < numPts; i++)
	{
		p = (*pline)[i].p;
		shape->object_to_current_coordsys(p);
		vl.result->append(new Point3Value(p));
	}
	return_value(vl.result);
}
 
  11 November 2013
two functions that appear in meshop interface but not the polyop. they are called from using something like

polyop.getMapVertsUsingMapFace $ 1 3
polyop.getMapFacesUsingMapVert $ 1 3


the ValueToBitArray to bit array function can be found in the common_functions.cpp of the mxsagni project in the samples.

void checkMapChannel(MNMesh* poly, int channel)
{
	range_check(channel, -NUM_HIDDENMAPS, MAX_MESHMAPS-1, GetString(IDS_MESH_MAP_CHANNEL_OUT_OF_RANGE));
	if (channel >= poly->numm)
		throw RuntimeError (GetString(IDS_MAP_SUPPORT_NOT_ENABLED_FOR_CHANNEL  ), Integer::intern(channel));
	if (poly->M(channel)->GetFlag(MN_DEAD))
		throw RuntimeError(GetString(IDS_MAP_SUPPORT_NOT_ENABLED  _FOR_CHANNEL), Integer::intern(channel));
}

//**************************************************  ******************************************

def_struct_primitive(polyop_getMapVertsUsingMapFac  e, polyop, "getMapVertsUsingMapFace");

// <bitarray> getMapVertsUsingMapFace   

Value* polyop_getMapVertsUsingMapFace_cf(Value** arg_list, int arg_count)
{
// the usual arg check

	check_arg_count(getMapVertsUsingMapFace, 3, arg_count);

// get the poly mesh

	MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_READ_ACCESS, NULL, getMapVertsUsingMapFace);

// get map channel arg and check for support and in range

	int channel = arg_list[1]->to_int();
	checkMapChannel(pmesh,channel);

// ok to access the map

	MNMap* map = pmesh->M(channel);
	int nMapVerts = map->numv;
	int nMapFaces = map->numf;

// create a new bitarray from input which could be a bitarray, int or array of ints

	BitArray mapFaces(nMapFaces);
	ValueToBitArray(arg_list[2], mapFaces, nMapFaces, GetString(IDS_POLY_MAP_FACE_INDEX_OUT_OF_RANGE));

// create the return variable on the stack

	one_typed_value_local(BitArrayValue* mapVerts);
	vl.mapVerts = new BitArrayValue(nMapVerts);

	for(int f = 0; f < nMapFaces; f++) // for all map faces
	{
		if(mapFaces[f]) // if set
		{
			MNMapFace* face = map->F(f); // get our face and
			for(int v = 0; v < face->deg; v++) // for all verts in the map face
				vl.mapVerts->bits.Set(face->tv[v]); // set the corresponding bit
		}
	}
	return_value(vl.mapVerts);
}

//**************************************************  ******************************************

def_struct_primitive(polyop_getMapFacesUsingMapVer  t, polyop, "getMapFacesUsingMapVert");

// <bitarray> getMapFacesUsingMapVert   

Value* polyop_getMapFacesUsingMapVert_cf(Value** arg_list, int arg_count)
{
// the usual arg check

	check_arg_count(getMapFacesUsingMapVert, 3, arg_count);

// get the poly mesh

	MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_READ_ACCESS, NULL, getMapFacesUsingMapVert);

// get map channel arg and check for support and in range

	int channel = arg_list[1]->to_int();
	checkMapChannel(pmesh,channel);

// ok to access the map

	MNMap* map = pmesh->M(channel);
	int nMapVerts = map->numv;
	int nMapFaces = map->numf;

// create a new bitarray from input which could be a bitarray, int or array of ints

	BitArray mapVerts(nMapVerts);
	ValueToBitArray(arg_list[2], mapVerts, nMapVerts, GetString(IDS_POLY_MAP_VERTEX_INDEX_OUT_OF_RANGE))  ;

// create the return variable on the stack

	one_typed_value_local(BitArrayValue* mapFaces);
	vl.mapFaces = new BitArrayValue (nMapFaces);

// iterate through the faces set the bit array if using the the verts
	
	for(int f = 0; f < nMapFaces; f++)
	{
		MNMapFace* face = map->F(f);
		for(int v = 0; v < face->deg; v++ ) // for all verts in the face
		{
			if(mapVerts[face->tv[v]]) // is this face using this vert ?
			{
				vl.mapFaces->bits.Set(f);
				break; // face is being used we don't need to know anymore
			}
		}
	}
	return_value(vl.mapFaces);
}
 
  12 December 2013
I'm sure there are ways to create meshes that defeat it both ways but it should work for most cases....


def_visible_primitive(isMeshClosed,"isMeshClosed");
 
 Value* isMeshClosed_cf(Value **arg_list, int count)
 {
 	check_arg_count(isMeshClosed, 1, count);
 	Mesh* pmesh = get_meshForValue(arg_list[0], MESH_READ_ACCESS, NULL, isMeshClosed);
 
 	int numEdges;
 	Edge* edges = pmesh->MakeEdgeList(&numEdges);
 	
 	BOOL openEdge = FALSE;
 	for(int i = 0; i < numEdges; ++i)
 	{
 		Edge& edge = edges[i];
 		if(edge.f[0] == -1 || edge.f[1] == -1)
 		{		
 			openEdge = TRUE;
 			break;
 		}
 	}
 	delete [] edges;
 	return bool_result(!openEdge);
 }

Last edited by Klunk : 12 December 2013 at 10:48 AM.
 
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 03:24 PM.


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