i was tired to take and use all this methods from different places of max… so there is an OPS:
/******** TimeOps ***********/
def_struct_primitive (timeOps_GetTicksPerFrame, timeOps, "GetTicksPerFrame");
Value* timeOps_GetTicksPerFrame_cf(Value** arg_list, int count)
{
check_arg_count(GetTicksPerFrame, 0, count);
return Integer::intern(GetTicksPerFrame());
}
def_struct_primitive (timeOps_SetTicksPerFrame, timeOps, "SetTicksPerFrame");
Value* timeOps_SetTicksPerFrame_cf(Value** arg_list, int count)
{
check_arg_count(SetTicksPerFrame, 1, count);
SetTicksPerFrame(arg_list[0]->to_int());
return Integer::intern(GetTicksPerFrame());
}
def_struct_primitive (timeOps_GetFrameRate, timeOps, "GetFrameRate");
Value* timeOps_GetFrameRate_cf(Value** arg_list, int count)
{
check_arg_count(GetFrameRate, 0, count);
return Integer::intern(GetFrameRate());
}
def_struct_primitive (timeOps_LegalFrameRate, timeOps, "LegalFrameRate");
Value* timeOps_LegalFrameRate_cf(Value** arg_list, int count)
{
check_arg_count(LegalFrameRate, 1, count);
return Integer::intern(LegalFrameRate(arg_list[0]->to_int()));
}
def_struct_primitive (timeOps_SetFrameRate, timeOps, "SetFrameRate");
Value* timeOps_SetFrameRate_cf(Value** arg_list, int count)
{
check_arg_count(SetFrameRate, 1, count);
SetFrameRate(arg_list[0]->to_int());
return Integer::intern(GetFrameRate());
}
/*
0 - Frame display format (DISPTIME_FRAMES)
1 - SMPTE time code format (DISPTIME_SMPTE)
2 - Frame:Ticks format (DISPTIME_FRAMETICKS)
3 - MM:SS:Ticks format (DISPTIME_TIMETICKS)
*/
def_struct_primitive (timeOps_GetTimeDisplayMode, timeOps, "GetTimeDisplayMode");
Value* timeOps_GetTimeDisplayMode_cf(Value** arg_list, int count)
{
check_arg_count(GetTimeDisplayMode, 0, count);
TimeDisp mode = GetTimeDisplayMode();
return Integer::intern(mode);
}
def_struct_primitive (timeOps_SetTimeDisplayMode, timeOps, "SetTimeDisplayMode");
Value* timeOps_SetTimeDisplayMode_cf(Value** arg_list, int count)
{
check_arg_count(SetTimeDisplayMode, 1, count);
SetTimeDisplayMode((TimeDisp)arg_list[0]->to_int());
return Integer::intern(GetTimeDisplayMode());
}
def_struct_primitive (timeOps_TimeToString, timeOps, "TimeToString");
Value* timeOps_TimeToString_cf(Value** arg_list, int count)
{
check_arg_count(TimeToString, 1, count);
MSTR str;
TimeToString(arg_list[0]->to_timevalue(), str);
return new String(str);
}
def_struct_primitive (timeOps_StringToTime, timeOps, "StringToTime");
Value* timeOps_StringToTime_cf(Value** arg_list, int count)
{
check_arg_count(StringToTime, 1, count);
TimeValue time;
StringToTime(arg_list[0]->to_string(), time);
return MSTime::intern(time);
}
def_struct_primitive (timeOps_TicksToSec, timeOps, "TicksToSec");
Value* timeOps_TicksToSec_cf(Value** arg_list, int count)
{
check_arg_count(TicksToSec, 1, count);
return Float::intern(TicksToSec(arg_list[0]->to_int()));
}
def_struct_primitive (timeOps_SecToTicks, timeOps, "SecToTicks");
Value* timeOps_SecToTicks_cf(Value** arg_list, int count)
{
check_arg_count(SecToTicks, 1, count);
return Integer::intern(SecToTicks(arg_list[0]->to_float()));
}
def_struct_primitive (timeOps_TicksSecToTime, timeOps, "TicksSecToTime");
Value* timeOps_TicksSecToTime_cf(Value** arg_list, int count)
{
check_arg_count(TicksSecToTime, 2, count);
return MSTime::intern(TicksSecToTime(arg_list[0]->to_int(), arg_list[1]->to_float()));
}
def_struct_primitive (timeOps_TimeToTicksSec, timeOps, "TimeToTicksSec");
Value* timeOps_TimeToTicksSec_cf(Value** arg_list, int count)
{
check_arg_count(TimeToTicksSec, 1, count);
TimeValue time = arg_list[0]->to_timevalue();
int ticks;
int secs;
TimeToTicksSec(time, ticks, secs);
Array* t = new Array(2);
t->append(Integer::intern(ticks));
t->append(Float::intern((float)secs));
return t;
}
some of these methods are not available at all via mxs
i don’t know why but max don’t give an option to set a spinner in readonly state…
here is an extension:
def_mapped_primitive(setSpinnerReadOnly, "setSpinnerReadOnly");
Value* setSpinnerReadOnly_cf(Value **arg_list, int count)
{
check_arg_count(setSpinnerReadOnly, 2, count);
if (is_rolloutcontrol(arg_list[0]))
{
RolloutControl *control = (RolloutControl*)arg_list[0];
HWND hwnd = GetDlgItem(control->parent_rollout->page, control->control_ID);
ISpinnerControl *sp = GetISpinner(hwnd);
if (sp)
{
BOOL readOnly = is_number(arg_list[1]) ? arg_list[1]->to_int() : arg_list[1]->to_bool();
SendMessage(hwnd, WM_SETREDRAW, !readOnly, 0);
hwnd = GetWindow(hwnd, GW_HWNDPREV);
hwnd = GetWindow(hwnd, GW_CHILD);
hwnd = GetWindow(hwnd, GW_CHILD);
if (readOnly) SendMessage(hwnd, WM_SETREDRAW, 1, 0);
SendMessage(hwnd, EM_SETREADONLY, readOnly, 0);
ReleaseISpinner(sp);
return IntegerPtr::intern((INT_PTR)hwnd);
}
}
return &undefined;
}
i’ve slightly modified the get soft selection color to add an option to return point3 value (for map channels)
and added a method to return vertices soft selection weight using a mesh and soft-selection set of parameters
def_visible_primitive(softSelectionColor, "softSelectionColor");
Value* softSelectionColor_cf(Value** arg_list, int count)
{
check_arg_count_with_keys(softSelectionColor, 1, count);
Point3 col = SoftSelectionColor(arg_list[0]->to_float());
if (key_arg(type) == n_color)
{
return new ColorValue(col * 255.0f);
}
return new Point3Value(col);
}
/*
BOOL useEdgeDist
If useEdgeDist is TRUE, the distance between vertices is computed along edges. If FALSE, it's computed directly through space.
int edgeIts
This indicates the maximum number of edges the algorithm may travel along in finding the distance between vertices. (Maximum path length.)
WARNING: If useEdgeDist is FALSE, this is an n-squared algorithm: it compares every vertex not in the cluster with every vertex in it. If useEdgeDist is TRUE, the time it takes is proportional to the number of verts in the cluster times edgeIts.
BOOL ignoreBack
If TRUE, vertices with a normal (as computed in VertexNormals) that points more than 90 degrees away from the average normal of theselection are not given any partial selections. They're either 1 if selected or 0 otherwise.
float falloff
The limit distance of the effect. If distance > falloff, the function will always return 0.
float pinch
Use this to affect the tangency of the curve near distance=0. Positive values produce a pointed tip, with a negative slope at 0, while negative values produce a dimple, with positive slope.
float bubble
Use this to change the curvature of the function. A value of 1.0 produces a half-dome. As you reduce this value, the sides of the dome slope more steeply. Negative values lower the base of the curve below 0.
*/
def_visible_primitive(getMeshVSWeights, "getMeshVSWeights");
Value* getMeshVSWeights_cf(Value** arg_list, int count)
{
check_arg_count_with_keys(getMeshVSWeights, 2, count);
Mesh* mesh = arg_list[0]->to_mesh();
if (mesh)
{
Array* dataArray = (Array*)arg_list[1];
BOOL useEdgeDist = dataArray->data[0]->to_bool();
int edgeIts = dataArray->data[1]->to_int();
BOOL arIgBack = dataArray->data[2]->to_bool();
float falloff = dataArray->data[3]->to_float();
float pinch = dataArray->data[4]->to_float();
float bubble = dataArray->data[5]->to_float();
if (is_bitarray(key_arg(selection)))
{
mesh->vertSel = key_arg(selection)->to_bitarray();
}
MeshTempData meshData(mesh);
float* vsweights = meshData.VSWeight(useEdgeDist, edgeIts, arIgBack, falloff, pinch, bubble)->Addr(0);
int numv = mesh->numVerts;
BOOL asColor = key_arg_or_default(color, &false_value)->to_bool();
Array* weights = new Array(numv);
if (asColor)
{
for (int k=0; k < numv; k++) weights->append(new ColorValue(SoftSelectionColor(vsweights[k])*255.0f));
}
else
{
for (int k=0; k < numv; k++) weights->append(Float::intern(vsweights[k]));
}
return weights;
}
return &undefined;
}
as an option you can set a vertex selection or use (default) the current one
nice one denis, I quite like this sort of thing for returns (though the ? operator was banned by the tech director at one place I worked )
that’s banned because of not being able for debugging…
i use it but only with simple type returned
(and another reason – in my function i can also return Point4 where w value might be an original weight or vertex index for example)
It wasn’t for debugging he just didn’t like it and can be sometimes confusing to read.
So, as I get stuff working. Here is collapse stack for for TriObject. This has the Undo turned off.
Any thoughts are always welcome, but it does work
void PolyTools::CollapseMesh(INode *node){
ICustAttribCollapseManager * iCM = ICustAttribCollapseManager::GetICustAttribCollapseManager();
TriObject *tobj = NULL;
Object *oldObj = node->GetObjectRef();
bool ignoreBaseObjectCAs = false;
if(iCM && iCM->GetCustAttribSurviveCollapseState()){
NotifyCollapseMaintainCustAttribEnumProc2 PreNCEP(true,node);
EnumGeomPipeline(&PreNCEP,oldObj);
}
else{
NotifyCollapseEnumProc PreNCEP(true,node);
EnumGeomPipeline(&PreNCEP,oldObj);
}
ObjectState os = oldObj->Eval(ip->GetTime());
HoldSuspend hs;
Object *obj = (Object*)os.obj->CollapseObject();
if(obj == os.obj){
Object *theBaseObject = oldObj->FindBaseObject();
if (obj == theBaseObject)
ignoreBaseObjectCAs = true;
obj = (Object*)CloneRefHierarchy(obj);
}
hs.Resume();
if (os.obj->CanConvertToType(triObjectClassID)) {
// Convert it to a TriObject and make that the new object
tobj = (TriObject*)obj->ConvertToType(ip->GetTime(),triObjectClassID);
if (tobj != obj)
ignoreBaseObjectCAs = false;
oldObj->SetAFlag(A_LOCK_TARGET);
node->SetObjectRef(tobj);
GetCOREInterface7()->InvalidateObCache(node);
node->NotifyDependents(FOREVER, 0, REFMSG_SUBANIM_STRUCTURE_CHANGED);
if(iCM && iCM->GetCustAttribSurviveCollapseState()){
NotifyCollapseMaintainCustAttribEnumProc2 PostNCEP(false,node,ignoreBaseObjectCAs,tobj);
EnumGeomPipeline(&PostNCEP,oldObj);
}
else{
NotifyCollapseEnumProc PostNCEP(false,node,tobj);
EnumGeomPipeline(&PostNCEP,oldObj);
}
oldObj->ClearAFlag(A_LOCK_TARGET);
oldObj->MaybeAutoDelete();
if (obj!=tobj) obj->MaybeAutoDelete();
}
ip->RedrawViews(ip->GetTime());
}
eh ? there’s already a perfectly good collapse stack routines exposed to mxs :shrug:
Yes, but I need to add more to this. I thought it might help someone.