Notifications
Clear all

[Closed] Useful mxs sdk extension functions

no self respecting maxscripter should be without their own sdk mxs function library. So here’s a thread to post those useful functions, speed ups and the like.

 So I'll kick off with a few...
def_visible_primitive(sortsf,"sortsf");
     
     struct float_compare 
     {
     	bool operator() (Value *a, Value *b) 
     	{ 
     		return  ascending ? ((Struct*)a)->member_data[index]->to_float() < ((Struct*)b)->member_data[index]->to_float() :
     					((Struct*)a)->member_data[index]->to_float() > ((Struct*)b)->member_data[index]->to_float();
     	}
     	int		index;
     	BOOL	ascending;
     
     	float_compare(int i, BOOL asc = true) : index(i), ascending(asc) {}
     };
     
     //********************************************************************************************
     // sort an array of structs based on the float value in a member field 
     // usage
     // sortsf <array of structs> <#struct_member_name> 
     
     Value* sortsf_cf(Value **arg_list, int count)
     {
     	Array* theArray = (Array*)arg_list[0];

// bum out early if passed and empty array, no need for nasty mxs ** system exception **

	if(theArray->size == 0)  return Integer::intern(0);

     	Struct* theStruct = (Struct*)theArray->data[0];	// use the first array element as the struct "template"
     	Value* temp;
     
     // default to ascending though set if specified by the caller
     
     	BOOL ascending = true;
     	if(count == 3)
     		ascending = arg_list[2]->to_bool();
     
     // gets the member data index from the hash table, return undefined if not present
     
     	if((temp = theStruct->definition->get_member_value(arg_list[1])) == NULL)
     		return &undefined;
     
     // create the sorting compare object with our index
     // this is 1 based but I think max adds a dummy struct member at index 0 so it works
     
     	float_compare compare(temp->to_int(),ascending); 
     
     // sort the array
     
     	std::sort(theArray->data, theArray->data + theArray->size, compare);
     	return Integer::intern(theArray->size);
     }
     
     //********************************************************************************************

Denis has extended it for a more general use here

 a couple of silly one that i find useful
def_visible_primitive(itob, "itob");
     def_visible_primitive(btoi, "btoi");
     
   // usage: <BooleanClass>itob <integer>
     Value* itob_cf(Value **arg_list, int count) { return bool_result(arg_list[0]->to_int());}
     
   // usage: <integer>itob <BooleanClass>
     Value* btoi_cf(Value **arg_list, int count) { return Integer::intern(arg_list[0]->to_bool() ? 1 : 0); }
192 Replies

universal sorter (slightly modifier and extended claude666’s code):


  struct prop_float_compare 
  {
  	bool operator() (Value *a, Value *b) 
  	{ 
  		bool result = (a->_get_property(prop)->to_float() < b->_get_property(prop)->to_float());
  		return (reverse) ? !(result) : result;
  	}
  	BOOL reverse;
  	Value* prop;
  	prop_float_compare(Value* i, BOOL reverse = false) : prop(i), reverse(reverse) {}
  };
  struct prop_string_compare 
  {
  	bool operator() (Value *a, Value *b) 
  	{ 
  		bool result = ::_stricmp(a->_get_property(prop)->to_string(), b->_get_property(prop)->to_string()) < 0;
  		return (reverse) ? !(result) : result;
  	}
  	BOOL reverse;
  	Value* prop;
  	prop_string_compare(Value* i, BOOL reverse = false) : prop(i), reverse(reverse) {}
  };
  
     
  def_visible_primitive(sortpv, "sortpv");
  Value* sortpv_cf(Value **arg_list, int count)
  {
  	check_arg_count_with_keys(sortpv, 2, count);
  	Array* theArray = static_cast<Array*>(arg_list[0]);
  	Value* prop = arg_list[1];
  	
  	Value *temp;
  	BOOL reverse = bool_key_arg(flip, temp, false);
  
  	Value* value = (*theArray)[0]->_get_property(prop);
  
  	if(is_float(value) || is_int(value) || is_time(value))
  	{
  		prop_float_compare compare(prop, reverse); 
  		std::sort(theArray->data, theArray->data + theArray->size, compare);
  	}
  	else
  	if(is_string(value) || is_name(value)) 
  	{
  		prop_string_compare compare(prop, reverse); 
  		std::sort(theArray->data, theArray->data + theArray->size, compare);
  	}
  	else return &undefined;
  
  	return Integer::intern(theArray->size);
  }
  

it sorts array by defined property…
an array of anything that has property
sortpv [flip:false]

sample:


  (
  	delete objects
  	bb = #()
  	bb += for k=1 to 4 collect (box height:(random 1. 30.))
  	bb += for k=1 to 4 collect (cylinder height:(random 1. 30.))
  	bb += for k=1 to 4 collect (pyramid height:(random 1. 30.))
  		
  	t1 = timestamp()
  	m1 = heapfree
  	sortpv bb #height flip:on
  	format ">> t:% m:%
" (timestamp() - t1) (m1 - heapfree)
  	for k=1 to bb.count do bb[k].pos.x += (k-1)*30
  )
  

another sample:


  try(form.close()) catch()
  (
  	global form = dotnetobject "Form"
  	form.ShowInTaskbar = off
  	form.AutoSize = on
  	form.AutoSizeMode = form.AutoSizeMode.GrowAndShrink
  	
  	bts = for k=0 to 10 collect
  	(
  		local bt = dotnetobject "button" 
  		bt.Bounds = dotnetobject "System.Drawing.Rectangle" 0 0 (random 10 100) 24
  		bt.tag = bt.Bounds.Width
  		bt
  	)
  	sortpv bts #tag
  	x = 0
  	for bt in bts do 
  	(
  		bt.Location.x = x
  		x += bt.Width
  	)
  	form.controls.addrange bts
  	
  	MaxHandleWrapper = dotnetobject "MaxCustomControls.Win32HandleWrapper" (dotnetobject "System.IntPtr" (windows.getmaxhwnd()))
  	form.Show MaxHandleWrapper
  	ok
  )
  

but… it’s kinda slow. because common for all values _get_property method is very slow. i don’t see any way to speed it up yet. any ideas?

but! it doesn’t take any memory

why is it sortpv? “sort per value” or ““sort per property value”

this one from my newer style “Function Publishing” library

#define range_check(_val, _lowerLimit, _upperLimit, _desc)					\
	if (_val < _lowerLimit || _val > _upperLimit) {							\
		TCHAR buf[256];														\
		TCHAR buf2[128];													\
		strcpy(buf,_desc);													\
		strcat(buf,_T(" < "));												\
		_snprintf(buf2, 128, _T("%g"), EPS(_lowerLimit));					\
		strcat(buf,buf2);													\
		strcat(buf,_T(" or > "));											\
		_snprintf(buf2, 128, _T("%g"), EPS(_upperLimit));					\
		strcat(buf,buf2);													\
		strcat(buf,_T(": "));												\
		_snprintf(buf2, 128, _T("%g"), EPS(_val));							\
		strcat(buf,buf2);													\
		throw RuntimeError (buf);											\
	}

MNMesh* getPolyMeshFromNode(INode* node, int accessType)
{
	MNMesh* poly = NULL;

	Object* obj = node->GetObjectRef();
	Object* base_obj = Get_Object_Or_XRef_BaseObject(obj);

	if(accessType == MESH_WRITE_ACCESS && obj != base_obj)
		throw RuntimeError(GetString(IDS_MODIFIER_PRESENT_ERR), obj->GetObjectName());
	else if(accessType == MESH_BASE_OBJ || accessType == MESH_WRITE_ACCESS)
	{
		if(base_obj->ClassID() != EPOLYOBJ_CLASS_ID)
			throw RuntimeError(GetString(IDS_OP_ON_NON_EPOLY), obj->GetObjectName());
		poly = &((PolyObject*)base_obj)->GetMesh();
	}
	else
	{
		ObjectState os = obj->Eval(MAXScript_time());
		obj = (Object*)os.obj;
		if(obj->ClassID() != EPOLYOBJ_CLASS_ID && obj->ClassID() != polyObjectClassID)
			throw RuntimeError(GetString(IDS_OP_ON_NON_EPOLY), obj->GetObjectName());
		poly = &((PolyObject*)obj)->GetMesh();
	}
	return poly;
}

void CFnLib::getMapVertsFromGeoVert(INode* node,  const int mapChannel, int vert, BitArray& mapverts)
{
// Get the mesh

   MNMesh* mesh = getPolyMeshFromNode(node, MESH_READ_ACCESS);
   if(mesh == NULL)
	  return;
	
// get the map

	MNMap* map = mesh->M(mapChannel);

// check for map support (something not workin' here!)

	if(map->GetFlag(MN_DEAD))
	{
		char buffer[33];
		throw RuntimeError("Map support not enabled for specified map channel: ", itoa(mapChannel,buffer,10));
	}

// check input bounds

	range_check(vert, 1, mesh->VNum(), "Map Vert Index Out of Range: ");	

// make sure input bitarray is the correct length

	mapverts.SetSize(map->VNum());
	mapverts.ClearAll();

// for all the faces
	
	int nFaces = mesh->FNum();
	for(int i=0; i < nFaces; i++)
	{
		MNFace*		geoface	= mesh->F(i);
		MNMapFace*	mapface	= map->F(i);

// skip over dead faces

		if(geoface->GetFlag(MN_DEAD)) 
			continue;

		int face_deg = geoface->deg;
		for(int j=0; j < face_deg; j++) 
		{
			if(geoface->vtx[j] == vert - 1)
			{
				mapverts.Set(mapface->tv[j]);
				break; // should only be one per face
			}
		}
	}
}

think it would be easily ported to the older Exposure Technique

here’s a few more lets you add “hidden” user data to a scene, uses the same owner class & super class id as the other mxs app data routines


 bool CFnLib::isSceneAppData(int id)
 {
 	return GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id) != 0;
 }
 
 // remove sceneapp data
 
 bool CFnLib::removeSceneAppData(int id)
 {
 	return GetCOREInterface()->GetScenePointer()->RemoveAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id) != 0;
 }
 
 void CFnLib::setSceneAppDataString(int id, const TCHAR* string)
 {
 	int len = strlen(string) + 1; // i'm guessing we'll need the terminator on return
 	char* cptr = (char *)MAX_malloc(len);
 	memcpy(cptr,string,len);
 
 // delete any old data
 
 	GetCOREInterface()->GetScenePointer()->RemoveAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
 
 // replace with new
 
 	GetCOREInterface()->GetScenePointer()->AddAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id, len, cptr);
 }
 
 
 TCHAR* CFnLib::getSceneAppDataString(int id)
 {
 	AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
 	if(appdata)
 		return ((TCHAR *)appdata->data);
 	return 0;
 }

following this thread http://forums.cgsociety.org/showthread.php?f=98&t=1031550


    #include "IPathConfigMgr.h"
 class PathConfigMgr : public FPInterfaceDesc
 {
 public:
 
 	static const Interface_ID id;
 	
 	enum FunctionIDs
 	{
 		_GetResolveUNC,
 		_SetResolveUNC,
 		_GetResolveToRelative,
 		_SetResolveToRelative,
 	};
 
 	PathConfigMgr() : FPInterfaceDesc(id, _M("PathConfigMgr"), 0, NULL, FP_CORE, end)
 	{
 		AppendFunction(
 			_GetResolveUNC, _M("GetResolveUNC"), 0, TYPE_BOOL, 0, 0, /* Number of arguments */
 			end); 
 		AppendFunction(
 			_SetResolveUNC, _M("SetResolveUNC"), 0, TYPE_BOOL, 0, 1, /* Number of arguments */
 				_M("flag"), 0, TYPE_BOOL,
 			end); 
 		AppendFunction(
 			_GetResolveToRelative, _M("GetResolveToRelative"), 0, TYPE_BOOL, 0, 0, /* Number of arguments */
 			end); 
 		AppendFunction(
 			_SetResolveToRelative, _M("SetResolveToRelative"), 0, TYPE_BOOL, 0, 1, /* Number of arguments */
 				_M("flag"), 0, TYPE_BOOL,
 			end); 
 	}
 
 	static bool GetResolveUNC() { 
 		return IPathConfigMgr::GetPathConfigMgr()->GetResolveUNC(); 
 	} 
 	static bool SetResolveUNC(BOOL flag) { 
 		bool prev = GetResolveUNC();
 		IPathConfigMgr::GetPathConfigMgr()->SetResolveUNC(flag == TRUE);
 		return prev; 
 	}
 	static bool GetResolveToRelative() { 
 		return IPathConfigMgr::GetPathConfigMgr()->GetResolveToRelative(); 
 	} 
 	static bool SetResolveToRelative(BOOL flag) {
 		bool prev = GetResolveToRelative();
 		IPathConfigMgr::GetPathConfigMgr()->SetResolveToRelative(flag == TRUE);
 		return prev; 
 	}
 
 	BEGIN_FUNCTION_MAP
 		FN_0(_GetResolveUNC, TYPE_BOOL, GetResolveUNC)
 		FN_1(_SetResolveUNC, TYPE_BOOL, SetResolveUNC, TYPE_BOOL)
 		FN_0(_GetResolveToRelative, TYPE_BOOL, GetResolveToRelative)
 		FN_1(_SetResolveToRelative, TYPE_BOOL, SetResolveToRelative, TYPE_BOOL)
 	END_FUNCTION_MAP
 
 };
 
 const Interface_ID PathConfigMgr::id = Interface_ID(0x62174bc6, 0x790c7394);
 static PathConfigMgr pathConfingExtInterface;
    
both [b]set [/b]functions return previous state of the property. 

max PathConfig interface doesn't provide these methods except GetResolveUNC.

it’s different to how I do those and I’m a little confused with…

static PathConfigMgr GetResolveUNC;
static PathConfigMgr SetResolveUNC;
static PathConfigMgr GetResolveToRelative;
static PathConfigMgr SetResolveToRelative;

isn’t that 4 instances of the same interface ? shouldn’t something like…

static  PathConfigMgr  pcmgrInterface;

suffice ?

you are right. it should be your way. it was a result of hasty copying.

i think you can loose the static on the member function definitions too, but other than than it’s a really cool and compact way of doing it, and can be dropped straight into another interface project cpp file as is and you’ve got another interface with none of that tedious setting up visual studio project build settings or creating a new interface class and inheriting from that. I like it

copy and paste, build 30 secs later


 showinterface PathConfigMgr
   Interface: PathConfigMgr
    Properties:
    Methods:
 	<boolean>GetResolveUNC()
 	<boolean>SetResolveUNC flag
 	<boolean>GetResolveToRelative()
 	<boolean>SetResolveToRelative flag
    Actions:
 OK

i liked it so much i switched my sceneappdata interface to a similar format…

//*****************************************************************************************
  
  class SceneAppData : public FPInterfaceDesc
  {
  public:
  
  	static const Interface_ID id;
  
  	enum functions
  	{		
  		_isdata,
  		_remove,
  		_setint,
  		_getint,
  		_setflag,
  		_getflag,
  		_clearflag,
  		_setstring,
  		_getstring,
  		_setfloat,
  		_getfloat,
  		_setpoint3,
  		_getpoint3,
  		_setinttab,
  		_getinttab,
  		_setinttabvalue,
  		_getinttabvalue,
  		_setfloattab,
  		_getfloattab,
  		_setfloattabvalue,
  		_getfloattabvalue
  	};
  
  	SceneAppData() : FPInterfaceDesc(id, _M("sceneAppData"), 0, NULL, FP_CORE, end)
  	{
  		AppendFunction(	
  			_isdata, _M("isData"), 0, TYPE_BOOL, 0, 1,
  			_M("id"), 0, TYPE_INT, end);
  
  		AppendFunction(	
  			_remove, _M("remove"), 0, TYPE_BOOL, 0, 1,
  			_M("id"), 0, TYPE_INT, end);
  
  		
  		AppendFunction(	
  			_setint, _M("setInt"), 0, TYPE_BOOL, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("value"), 0, TYPE_INT, end);
  
  		AppendFunction(	
  			_getint, _M("getInt"), 0, TYPE_INT, 0, 1,
  			_M("id"), 0, TYPE_INT, end);
  
  		AppendFunction(	
  			_setflag, _M("setFlag"), 0, TYPE_BOOL, 0, 3,
  			_M("id"), 0, TYPE_INT,
  			_M("flag"), 0, TYPE_INT,
  			_M("setto"), 0, TYPE_INT, end);
  
  		AppendFunction(	
  			_getflag, _M("getFlag"), 0, TYPE_INT, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("flag"), 0, TYPE_INT, end);
  
  		AppendFunction(	
  			_clearflag, _M("clearFlag"), 0, TYPE_BOOL, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("flag"), 0, TYPE_INT,end);
  
  		AppendFunction(	
  			_setstring, _M("setString"), 0, TYPE_BOOL, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("string"), 0, TYPE_STRING, end);
  
  		AppendFunction(	
  			_getstring, _M("getString"), 0, TYPE_STRING, 0, 1,
  			_M("id"), 0, TYPE_INT, end);
  		AppendFunction(	
  			_setfloat, _M("setFloat"), 0, TYPE_BOOL, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("float"), 0, TYPE_FLOAT, end);
  
  		AppendFunction(	
  			_getfloat, _M("getFloat"), 0, TYPE_FLOAT, 0, 1,
  			_M("id"), 0, TYPE_INT, end);
  
  		AppendFunction(	
  			_setpoint3, _M("setPoint3"), 0, TYPE_BOOL, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("point3"), 0, TYPE_POINT3, end);
  
  		AppendFunction(	_getpoint3, _M("getPoint3"), 0, TYPE_POINT3, 0, 1,
  			_M("id"), 0, TYPE_INT, end);
  
  		AppendFunction(	
  			_setinttab, _M("setIntTab"), 0, TYPE_BOOL, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("int array"), 0, TYPE_INT_TAB_BR, end);
  
  		AppendFunction(	
  			_getinttab, _M("getIntTab"), 0, TYPE_INT, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("int array"), 0, TYPE_INT_TAB_BR, end);
  
  		AppendFunction(	
  			_setinttabvalue, _M("setIntTabValue"), 0, TYPE_BOOL, 0, 3,
  			_M("id"), 0, TYPE_INT,
  			_M("value"), 0, TYPE_INT,
  			_M("index"), 0, TYPE_INT, end);
  
  		AppendFunction(	
  			_getinttabvalue, _M("getIntTabValue"), 0, TYPE_INT, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("index"), 0, TYPE_INT,  end);
  
  		AppendFunction(	
  			_setfloattab, _M("setFloatTab"), 0, TYPE_BOOL, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("float array"), 0, TYPE_FLOAT_TAB_BR,  end);
  
  		AppendFunction(	
  			_getfloattab, _M("getFloatTab"), 0, TYPE_INT, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("float array"), 0, TYPE_FLOAT_TAB_BR,  end);
  
  		AppendFunction(	
  			_setfloattabvalue, _M("setFloatTabValue"), 0, TYPE_BOOL, 0, 3,
  			_M("id"), 0, TYPE_INT,
  			_M("value"), 0, TYPE_FLOAT,
  			_M("index"), 0, TYPE_INT,  end);
  
  		AppendFunction(	
  			_getfloattabvalue, _M("getFloatTabValue"), 0, TYPE_FLOAT, 0, 2,
  			_M("id"), 0, TYPE_INT,
  			_M("index"), 0, TYPE_INT,  end);
  	}
  
  //**************************************************************************************
  
  // <bool> sceneAppData.isData   
  
  	bool isData(int id)
  	{
  		return GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id) != 0;
  	}
  
  // <bool> sceneAppData.remove  
  
  	bool remove(int id)
  	{
  		return GetCOREInterface()->GetScenePointer()->RemoveAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id) != 0;
  	}
  
  //*****************************************************************************************
  
  // <bool> sceneAppData.setInt   
  
  	bool setInt(int id, int value);
  
  // <int> sceneAppData.getInt   
  
  	int getInt(int id)
  	{
  		AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  		if(appdata)
  			return *((int *)appdata->data);
  		return 0;
  	}
  
  //********************************************************************************************
  
  // <bool> sceneAppData.setFlag    
  
  	bool setFlag(int id, int f, int set)
  	{
  		AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id);  
  		if(appdata)
  		{
  			set ? *((int *)appdata->data) |= (1 << f) : *((int *)appdata->data) &= ~(1 << f);
  			return true;
  		}
  		else 
  			return setInt(id, (1 << f)); // create the appdata value as our flag.
  	}
  
  // <bool> sceneAppData.clearFlag    
  
  	bool clearFlag( int id, int f)
  	{
  		AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id);  
  		if(appdata)
  		{
  			*((int *)appdata->data) &= ~(1 << f);
  			return true;
  		}
  		else
  			return setInt(id, 0);
  	}
  
  // <bool> sceneAppData.getFlag    
  
  	int getFlag(int id, int f)
  	{
  		AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id);  
  		if(appdata)
  			return (int)((*((int *)appdata->data) & (1 << f)) != 0);
  		else
  			return 0;
  	}
  
  //********************************************************************************************
  
  // <bool> sceneAppData.setString    
  
  	bool setString(int id, const TCHAR* string);
  
  // <string> sceneAppData.getString 
  
  	TCHAR* getString(int id)
  	{
  		AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  		if(appdata)
  			return ((TCHAR *)appdata->data);
  		return 0;
  	}
  
  //********************************************************************************************
  
  // <bool> sceneAppData.setFloat    
  
  	bool setFloat(int id, float value);
  
  // <float> sceneAppData.getString 
  
  	float getFloat(int id)
  	{
  		AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  		if(appdata)
  			return *((float *)appdata->data);
  		return 0.0f;
  	}
  
  //********************************************************************************************
  
  // <bool> sceneAppData.setPoint3    
  
  	bool setPoint3(int id, Point3& p);
  
  // <Point3> sceneAppData.getPoint3  
  
  	Point3* getPoint3(int id)
  	{
  		AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  		if(appdata)
  			return (Point3 *)appdata->data;
  		return NULL; // mxs sees this as undefined which is nice
  	}
  
  //*****************************************************************************************
  
  // <bool> sceneAppData.setIntTab  
  
  	bool setIntTab(int id, Tab<int>& intTab);
  
  // <int> sceneAppData.getIntTab  
  
  	int	getIntTab(int id, Tab<int>& intTab);
  
  // <bool> sceneAppData.setIntTabValue   
  
  	bool setIntTabValue(int id, int value, int index);
  
  // <int> sceneAppData.getIntTabValue   
  
  	int getIntTabValue(int id, int index);
  
  //**************************************************************************************
  
  // <bool> sceneAppData.setFloatTab  
  
  	bool setFloatTab(int id, Tab<float>& floatTab);
  
  // <int> sceneAppData.getFloatTab  
  
  	int  getFloatTab(int id, Tab<float>& floatTab);
  
  // <bool> sceneAppData.setFloatTabValue   
  
  	bool setFloatTabValue(int id, float value, int index);
  
  // <float> sceneAppData.getFloatTabValue   
  
  	float getFloatTabValue(int id, int index);
  
  	BEGIN_FUNCTION_MAP
  		FN_1(_isdata, TYPE_BOOL, isData, TYPE_INT);
  		FN_1(_remove, TYPE_BOOL, remove, TYPE_INT);
  
  		FN_2(_setint, TYPE_BOOL, setInt, TYPE_INT, TYPE_INT);
  		FN_1(_getint, TYPE_INT, getInt, TYPE_INT);
  
  		FN_3(_setflag, TYPE_BOOL, setFlag, TYPE_INT, TYPE_INT, TYPE_INT);
  		FN_2(_getflag, TYPE_INT, getFlag,  TYPE_INT, TYPE_INT);
  		FN_2(_clearflag, TYPE_BOOL, clearFlag, TYPE_INT, TYPE_INT);
  
  		FN_2(_setstring, TYPE_BOOL, setString, TYPE_INT, TYPE_STRING);
  		FN_1(_getstring, TYPE_STRING, getString, TYPE_INT);
  
  		FN_2(_setfloat, TYPE_BOOL,setFloat, TYPE_INT, TYPE_FLOAT);
  		FN_1(_getfloat, TYPE_FLOAT, getFloat, TYPE_INT);
  
  		FN_2(_setpoint3, TYPE_BOOL, setPoint3,  TYPE_INT, TYPE_POINT3);
  		FN_1(_getpoint3, TYPE_POINT3, getPoint3, TYPE_INT);
  
  		FN_2(_setinttab, TYPE_BOOL, setIntTab, TYPE_INT, TYPE_INT_TAB_BR);
  		FN_2(_getinttab, TYPE_INT, getIntTab, TYPE_INT, TYPE_INT_TAB_BR);
  
  		FN_3(_setinttabvalue, TYPE_BOOL, setIntTabValue, TYPE_INT, TYPE_INT, TYPE_INT);
  		FN_2(_getinttabvalue, TYPE_INT, getIntTabValue, TYPE_INT, TYPE_INT);
  
  		FN_2(_setfloattab, TYPE_BOOL, setFloatTab, TYPE_INT, TYPE_FLOAT_TAB_BR);
  		FN_2(_getfloattab, TYPE_INT, getFloatTab, TYPE_INT, TYPE_FLOAT_TAB_BR);
  
  		FN_3(_setfloattabvalue, TYPE_BOOL,setFloatTabValue, TYPE_INT, TYPE_FLOAT, TYPE_INT);
  		FN_2(_getfloattabvalue, TYPE_FLOAT, getFloatTabValue, TYPE_INT, TYPE_INT);
  	END_FUNCTION_MAP
  };
  
  const Interface_ID SceneAppData::id = Interface_ID(0x9da3ed5, 0x6f30132b);
  static SceneAppData SceneAppDataInterface;
  
  //*****************************************************************************************
  
  bool SceneAppData::setInt(int id, int value)
  {
  	int* iptr = (int *)MAX_malloc(sizeof(int));
  	if(!iptr) return false;
  	*iptr = value;
  	GetCOREInterface()->GetScenePointer()->RemoveAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	GetCOREInterface()->GetScenePointer()->AddAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id, sizeof(int), iptr);
  	return true;
  }
  
  //********************************************************************************************
  
  bool SceneAppData::setString(int id, const TCHAR* string)
  {
  	int len = strlen(string) + 1; 
  	char* cptr = (char *)MAX_malloc(len);
  	if(!cptr) return false;
  	memcpy(cptr,string,len);
  	GetCOREInterface()->GetScenePointer()->RemoveAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	GetCOREInterface()->GetScenePointer()->AddAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id, len, cptr);
  	return true;
  }
  
  //********************************************************************************************
  
  bool SceneAppData::setFloat(int id, float value)
  {
  	float* fptr = (float *)MAX_malloc(sizeof(float));
  	if(!fptr) return false;
  	*fptr = value;
  	GetCOREInterface()->GetScenePointer()->RemoveAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	GetCOREInterface()->GetScenePointer()->AddAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id, sizeof(float), fptr);
  	return true;
  }
  
  //********************************************************************************************
  
  bool SceneAppData::setPoint3(int id, Point3& p)
  {
  	float* fptr = (float *)MAX_malloc(sizeof(Point3));
  	if(!fptr) return false;
  	memcpy(fptr,&p.x,sizeof(Point3));
  	GetCOREInterface()->GetScenePointer()->RemoveAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	GetCOREInterface()->GetScenePointer()->AddAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id, sizeof(Point3), fptr);
  	return true;
  }
  
  //********************************************************************************************
  
  bool SceneAppData::setIntTab(int id, Tab<int>& intTab)
  {
  	int numbytes = intTab.Count() * sizeof(int);
  	int* iptr = (int *)MAX_malloc(numbytes);
  	if(!iptr) return false;
  	memcpy(iptr,intTab.Addr(0),numbytes);
  	GetCOREInterface()->GetScenePointer()->RemoveAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	GetCOREInterface()->GetScenePointer()->AddAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id, numbytes, iptr);
  	return true;
  }
  
  //********************************************************************************************
  
  int SceneAppData::getIntTab(int id, Tab<int>& intTab)
  {
  	AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	if(appdata)
  	{
  		int number_of_ints = appdata->length/sizeof(int);
  		intTab.SetCount(number_of_ints);
  		memcpy(intTab.Addr(0),appdata->data,appdata->length);
  		return number_of_ints;
  	}
  	return 0;
  }
  
  //********************************************************************************************
  
  bool SceneAppData::setIntTabValue(int id, int value, int index)
  {
  	AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	if(appdata)
  	{
  		int number_of_ints = appdata->length/sizeof(int);
  		range_check(index, 1, number_of_ints, "Int Array Index Out of Range: ");
  		((int *)appdata->data)[index - 1] = value;
  		return true;
  	}
  	return false;
  }
  
  //********************************************************************************************
  
  int SceneAppData::getIntTabValue(int id, int index)
  {
  	AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	if(appdata)
  	{
  		int number_of_ints = appdata->length/sizeof(int);
  		range_check(index, 1, number_of_ints, "Int Array Index Out of Range: ");	
  		return ((int *)appdata->data)[index - 1];
  	}
  	return 0;
  }
  
  //********************************************************************************************
  
  bool SceneAppData::setFloatTab(int id, Tab<float>& floatTab)
  {
  	int numbytes = floatTab.Count() * sizeof(float);
  	float* fptr = (float *)MAX_malloc(numbytes);
  	if(!fptr) return false;
  	memcpy(fptr,floatTab.Addr(0),numbytes);
  	GetCOREInterface()->GetScenePointer()->RemoveAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	GetCOREInterface()->GetScenePointer()->AddAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id, numbytes, fptr);
  	return true;
  }
  
  //********************************************************************************************
  
  int SceneAppData::getFloatTab(int id, Tab<float>& floatTab)
  {
  	AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	if(appdata)
  	{
  		int number_of_floats = appdata->length/sizeof(float);
  		floatTab.SetCount(number_of_floats);
  		memcpy(floatTab.Addr(0),appdata->data,appdata->length);
  		return number_of_floats;
  	}
  	return 0;
  }
  
  //********************************************************************************************
  
  bool SceneAppData::setFloatTabValue(int id, float value, int index)
  {
  	AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	if(appdata)
  	{
  		int number_of_floats = appdata->length/sizeof(float);
  		range_check(index, 1, number_of_floats, "Float Array Index Out of Range: ");	
  		((float *)appdata->data)[index - 1] = value; 
  		return true;
  	}
  	return false;
  }
  
  //********************************************************************************************
  
  float SceneAppData::getFloatTabValue(int id, int index)
  {
  	AppDataChunk* appdata = GetCOREInterface()->GetScenePointer()->GetAppDataChunk(MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id); 
  	if(appdata)
  	{
  		int number_of_floats = appdata->length/sizeof(float);
  		range_check(index, 1, number_of_floats, "Float Array Index Out of Range: ");	
  		return ((float *)appdata->data)[index - 1];	
  	}
  	return 0;
  }
  
  //********************************************************************************************

the range_check macro can be found in \maxsdk\samples\maxscript\mxsagni\mxsagni.h. This interface can easily ported to hang the data off a node. Also the page encoding system seems to have stripped some of the comment description of the mxs call but it’s pretty easy to work out.

Page 1 / 18