[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); }
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
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 ?
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.