this one covers some old ground Denis
return the triangles that make up a poly face… if corner_index is set to false then it returns the vert index else it returns the face corner index
//********************************************************************************************
// getPolyTriangles
// mxs exposure
def_visible_primitive(getPolyTriangles,"getPolyTriangles");
// usage: <bool> getPolyTriangles <edit_poly node> <int face> <bool corner_index>
Value* getPolyTriangles_cf(Value **arg_list, int count)
{
check_arg_count(getPolyTriangles, 3, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_READ_ACCESS, NULL, getPolyTriangles);
int face = arg_list[1]->to_int() - 1;
range_check(face,0,(pmesh->numf - 1), GetString(IDS_FACE_INDEX_OUT_OF_RANGE));
int corner_index = arg_list[2]->to_bool();
Tab<int> tri;
pmesh->f[face].GetTriangles(tri);
// create the return array
int tri_count = tri.Count();
one_typed_value_local(Array* result);
vl.result = new Array(tri_count);
// copy data
for(int i=0; i < tri_count; i++)
corner_index ? vl.result->append(Integer::intern(tri[i] + 1)) :
vl.result->append(Integer::intern(pmesh->f[face].vtx[tri[i]] + 1)) ;
return_value(vl.result);
}
the range_check & get_polyForValue macros can be found in maxsdk\samples\maxscript\mxsagni\MXSAgni.h and the function get_polyForValue calls (_get_polyForValue) can be found in maxsdk\samples\maxscript\mxsagni\common_funcs.cpp
“hidden” interior edges can then be found with
fn GetInteriorEdges tris = (for v = 1 to (tris.count - 3) by 3 collect #(tris[v],tris[v+2]);)
where tris is the output from getPolyTriangles
this turns out to be a real time saver.
def_visible_primitive(getEdgeLength,"getEdgeLength");
// <float> getEdgeLength <Poly poly> <int edge>
Value* getEdgeLength_cf(Value** arg_list, int count)
{
check_arg_count(getEdgeLength, 2, count);
// get the mesh
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_READ_ACCESS, NULL, getEdgeLength);
// get the edge
int edge = arg_list[1]->to_int() - 1; // mxs to sdk
range_check(edge,0,(pmesh->nume - 1), GetString(IDS_EDGE_INDEX_OUT_OF_RANGE));
// return the length
return Float::intern(Distance(pmesh->v[pmesh->E(edge)->v1].p,pmesh->v[pmesh->E(edge)->v2].p));
}
distance would be your preferred function and the poly mesh functions and range check macro are as before.
it’s the real saver…get-angle-between-edge-faces function is needed to keep the company
comes in two flavours simple and proper, though proper is twice as slow as simple and simple is about 8x (on 2 quad object) faster than mxs. On a 3200 poly object its 128x faster
// a simplistic face edge angle
def_visible_primitive(getEdgeFaceAngle,"getEdgeFaceAngle");
// <float> getEdgeFaceAngle <Poly poly> <int edge>
Value* getEdgeFaceAngle_cf(Value** arg_list, int count)
{
check_arg_count(getEdgeFaceAngle, 2, count);
// get the mesh
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_READ_ACCESS, NULL, getEdgeFaceAngle);
// get the edge
int edge = arg_list[1]->to_int() - 1; // mxs to sdk
range_check(edge,0,(pmesh->nume - 1), GetString(IDS_EDGE_INDEX_OUT_OF_RANGE));
// He is dead, Jim
if(pmesh->E(edge)->GetFlag(MN_DEAD))
return &undefined;
// we have an open edge
if(pmesh->E(edge)->f2 == -1)
return Float::intern(1.0f);
// return the dot
return Float::intern( pmesh->GetFaceNormal(pmesh->E(edge)->f1,true) % pmesh->GetFaceNormal(pmesh->E(edge)->f2,true) );
}
// the proper method face edge angle
def_visible_primitive(getEdgeFaceAngleReflex,"getEdgeFaceAngleReflex");
// <float> getEdgeFaceAngleReflex <Poly poly> <int edge> <int& reflex>
Value* getEdgeFaceAngleReflex_cf(Value** arg_list, int count)
{
check_arg_count(getEdgeFaceAngleReflex, 3, count);
// get the mesh
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_READ_ACCESS, NULL, getEdgeFaceAngleReflex);
// get the edge
int edge = arg_list[1]->to_int() - 1; // mxs to sdk
range_check(edge,0,(pmesh->nume - 1), GetString(IDS_EDGE_INDEX_OUT_OF_RANGE));
MNEdge* pedge = pmesh->E(edge);
// set the reflex thunk
Thunk* reflexThunk = arg_list[2]->to_thunk();
// He is dead, Jim
if(pedge->GetFlag(MN_DEAD))
return &undefined;
// we have an open edge
if(pedge->f2 == -1)
{
reflexThunk->assign(Integer::intern(1));
return Float::intern(1.0f);
}
// get spare f1 spare vert
MNFace* f1 = pmesh->F(pedge->f1);
Point3& c1 = pmesh->v[f1->vtx[f1->FindTriPoint(f1->EdgeIndex(edge))]].p;
// compute normal
Point3& a = pmesh->v[pedge->v1].p;
Point3& b = pmesh->v[pedge->v2].p;
Point3 ab = b - a;
Point3 ac = c1 - a;
Point3 n1 = (ab ^ ac).Normalize();
// compute matrix
Matrix3 mat;
MatrixFromNormal(n1, mat);
mat.SetTranslate(a);
// get spare f2 spare vert
MNFace* f2 = pmesh->F(pedge->f2);
Point3& c2 = pmesh->v[f2->vtx[f2->FindTriPoint(f2->EdgeIndex(edge))]].p;
// compute normal
Point3 bc = c2 - b;
Point3 n2 = (bc ^ ab).Normalize();
// transform spare vert into f1 coordsys
Point3 c2_in_f1 = c2 * Inverse(mat);
// if c2_in_f1.z neg reflex = true
reflexThunk->assign(Integer::intern(c2_in_f1.z < 0.0f ? 1 : 0));
// return the dot
return Float::intern(n1 % n2);
}
very very nice. thank you. i will definitely add it to the extension that i use
a cleaner version (though no faster, think the bottle neck is in findtripoint & EdgeIndex) using plane equation to see if the angle is reflex. Also removed the thunk and poke the reflex param directly so no need for the “&”…
edit: put the thunk back as the direct access was having strange effect on the indexing conversion between mxs & sdk 😮
def_visible_primitive(getEdgeFaceAngleReflex,"getEdgeFaceAngleReflex");
// <float> getEdgeFaceAngleReflex <Poly poly> <int edge> <int& reflex>
Value* getEdgeFaceAngleReflex_cf(Value** arg_list, int count)
{
check_arg_count(getEdgeFaceAngleReflex, 3, count);
// get the mesh
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_READ_ACCESS, NULL, getEdgeFaceAngleReflex);
// get the edge
int edge = arg_list[1]->to_int() - 1; // mxs to sdk
range_check(edge,0,(pmesh->nume - 1), GetString(IDS_EDGE_INDEX_OUT_OF_RANGE));
MNEdge* pedge = pmesh->E(edge);
// set the reflex thunk
Thunk* reflexThunk = arg_list[2]->to_thunk();
// He is dead, Jim
if(pedge->GetFlag(MN_DEAD))
return &undefined;
// we have an open edge
if(pedge->f2 == -1)
{
reflexThunk->assign(Integer::intern(1));
return Float::intern(1.0f);
}
// get spare f1 spare vert
MNFace* face = pmesh->F(pedge->f1);
Point3& c1 = pmesh->v[face->vtx[face->FindTriPoint(face->EdgeIndex(edge))]].p;
// compute f1 normal
Point3& a = pmesh->v[pedge->v1].p;
Point3& b = pmesh->v[pedge->v2].p;
Point3 ab = b - a;
Point3 ac = c1 - a;
Point3 n1 = (ab ^ ac).FNormalize();
// define the plane
float d = n1 % c1;
// get spare f2 spare vert
face = pmesh->F(pedge->f2);
Point3& c2 = pmesh->v[face->vtx[face->FindTriPoint(face->EdgeIndex(edge))]].p;
// compute f2 normal
Point3 bc = c2 - b;
Point3 n2 = (bc ^ ab).FNormalize();
// is c2 below the plane defined by n1 & d
reflexThunk->assign(Integer::intern((n1 % c2) - d < 0.0f ? 1 : 0));
// return the dot
return Float::intern(n1 % n2);
}
edit: have found more efficient way of doing this in mxs and the performance is on average only 5/6 times better.
following this thread http://forums.cgsociety.org/showthread.php?f=98&t=1090733
i wrote this function…
def_visible_primitive(patchAttach, "patchAttach");
Value* patchAttach_cf(Value **arg_list, int count)
{
check_arg_count(patchAttach, 2, count);
INode *patch = arg_list[0]->to_node();
INode *node = arg_list[1]->to_node();
if (patch == node) return &false_value;
Object* obj = Get_Object_Or_XRef_BaseObject(patch->GetObjectRef());
if (obj->ClassID() == patchObjectClassID)
{
PatchObject *ep = dynamic_cast<PatchObject *>(obj);
GeomObject *object = (GeomObject*)node->GetObjectRef()->Eval(MAXScript_interface->GetTime()).obj;
if(object->CanConvertToType(patchObjectClassID)) {
PatchObject *attPatch = (PatchObject*)object->ConvertToType(MAXScript_interface->GetTime(),patchObjectClassID);
if(attPatch) {
PatchMesh source = attPatch->patch;
bool canUndo = true;
ep->DoAttach(node, &source, canUndo);
if(attPatch != (PatchObject*)object) delete attPatch;
return &true_value;
}
}
}
return &false_value;
}
it uses DoAttach which very old, and as many other methods of that time needs to be executed when patch is selected and it is in modifier panel…
it’s possible to use a lower level (PatchMesh) Attach but it needs more work.
the code is primitive the function might be useful:
def_visible_primitive(abortRender, "abortRender");
Value* abortRender_cf(Value **arg_list, int count)
{
check_arg_count(patchAttach, 0, count);
MAXScript_interface->AbortRender();
return MAXScript_interface->CheckForRenderAbort() ? &true_value : &false_value;
}
mxs use:
fn preRenderAbort event: =
(
format "% >> % %
" event (callbacks.notificationparam()) (abortRender())
)
callbacks.removescripts id:#render_test
callbacks.addscript #preRender "preRenderAbort event:#preRender" id:#render_test
callbacks.addscript #preRenderEval "preRenderAbort event:#preRenderEval" id:#render_test
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....
hasSpecifiedNormals, checks for the MNNormalSpec is present, though this maybe empty
[b]usage: <bool> hasSpecifiedNormals <edit_poly_node>[/b]
def_visible_primitive(hasSpecifiedNormals,"hasSpecifiedNormals");
Value* hasSpecifiedNormals_cf(Value **arg_list, int count)
{
check_arg_count(hasSpecifiedNormals, 1, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, hasSpecifiedNormals);
return bool_result(pmesh->GetSpecifiedNormals());
}
clearSpecifiedNormals, clear specified normals from an editable poly
[b]usage: <bool> clearSpecifiedNormals <edit_poly_node>[/b]
def_visible_primitive(clearSpecifiedNormals,"clearSpecifiedNormals");
Value* clearSpecifiedNormals_cf(Value **arg_list, int count)
{
check_arg_count(clearSpecifiedNormals, 1, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, clearSpecifiedNormals);
if(pmesh->GetSpecifiedNormals())
{
pmesh->ClearSpecifiedNormals();
return &true_value;
}
else
return &false_value;
}
buildSpecifiedNormals, builds specified normals for an editable poly caution this clears any current specified normals before rebuilding the normals
[b]usage: <bool> buildSpecifiedNormals <edit_poly_node>[/b]
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();
return &true_value;
}
}
return &false_value;
}
getNumSpecNormalFaces, returns the number of specified normal faces
[b]usage: <int> getNumSpecNormalFaces <edit_poly_node>[/b]
def_visible_primitive(getNumSpecNormalFaces,"getNumSpecNormalFaces");
Value* getNumSpecNormalFaces_cf(Value **arg_list, int count)
{
check_arg_count(getNumSpecNormalFaces, 1, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, getNumSpecNormalFaces);
int numfaces = 0;
MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
if(nspec)
numfaces = nspec->GetNumFaces();
return Integer::intern(numfaces);
}
getNumSpecNormals, returns the number of specified normals
[b]usage: <int> getNumSpecNormals <edit_poly_node>[/b]
def_visible_primitive(getNumSpecNormals,"getNumSpecNormals");
Value* getNumSpecNormals_cf(Value **arg_list, int count)
{
check_arg_count(getNumSpecNormals, 1, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, getNumSpecNormalFaces);
int numNormals = 0;
MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
if(nspec)
numNormals = nspec->GetNumNormals();
return Integer::intern(numNormals);
}
setAllSpecNormalsExplicit , sets all normals explicit or not
[b]usage: <bool> setAllSpecNormalsExplicit <edit_poly_node> <bool flag>[/b]
def_visible_primitive(setAllSpecNormalsExplicit,"setAllSpecNormalsExplicit");
Value* setAllSpecNormalsExplicit_cf(Value **arg_list, int count)
{
check_arg_count(setAllSpecNormalsExplicit, 2, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, setAllSpecNormalsExplicit);
MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
if(nspec)
{
nspec->MakeNormalsExplicit(false, NULL ,arg_list[1]->to_bool());
return &true_value;
}
return &false_value;
}
setAllSpecNormalsSpecified , sets all normals explicit or not
[b]usage: <bool> setAllSpecNormalsSpecified <edit_poly_node> <bool flag>[/b]
def_visible_primitive(setAllSpecNormalsSpecified,"setAllSpecNormalsSpecified");
Value* setAllSpecNormalsSpecified_cf(Value **arg_list, int count)
{
check_arg_count(setAllSpecNormalsSpecified, 2, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, setAllSpecNormalsSpecified);
MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
if(nspec)
{
nspec->SpecifyNormals(false, NULL);
return &true_value;
}
return &false_value;
}
resetAllSpecNormals , resets all normals which are then recalculated
[b]usage: <bool> resetAllSpecNormals <edit_poly_node>[/b]
def_visible_primitive(resetAllSpecNormals,"resetAllSpecNormals");
Value* resetAllSpecNormals_cf(Value **arg_list, int count)
{
check_arg_count(resetAllSpecNormals, 1, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, resetAllSpecNormals);
MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
if(nspec)
{
nspec->ResetNormals(false,NULL);
return &true_value;
}
return &false_value;
}
setSpecNormal , sets the normal value
[b]usage: <bool> setSpecNormal <edit_poly_node> <int normal_id> <point3 normal>[/b]
def_visible_primitive(setSpecNormal,"setSpecNormal");
Value* setSpecNormal_cf(Value **arg_list, int count)
{
check_arg_count(setSpecNormal, 3, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, setSpecNormal);
MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
if(nspec)
{
int normalID = arg_list[1]->to_int() - 1;
range_check(normalID,0,(nspec->GetNumNormals() - 1), GetString(IDS_NORMAL_INDEX_OUT_OF_RANGE));
nspec->Normal(normalID) = arg_list[2]->to_point3();
return &true_value;
}
return &false_value;
}
getSpecNormal , gets the normal value
[b]usage: <point3> getSpecNormal <edit_poly_node> <int normal_id>
[/b]
def_visible_primitive(getSpecNormal,"getSpecNormal");
Value* getSpecNormal_cf(Value **arg_list, int count)
{
check_arg_count(getSpecNormal, 2, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, getSpecNormal);
MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
if(nspec)
{
int normalID = arg_list[1]->to_int() - 1;
range_check(normalID,0 ,(nspec->GetNumNormals() - 1), GetString(IDS_NORMAL_INDEX_OUT_OF_RANGE));
return new Point3Value(nspec->Normal(normalID));
}
return &undefined;
}
getSpecNormalIndex , gets the normal index from the face and corner (1..to facedeg)
[b]usage: <int> getSpecNormalIndex <edit_poly_node> <int face> <int corner>[/b]
def_visible_primitive(getSpecNormalIndex,"getSpecNormalIndex");
Value* getSpecNormalIndex_cf(Value **arg_list, int count)
{
check_arg_count(getSpecNormalIndex, 3, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, getSpecNormalIndex);
MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
if(nspec)
{
int face = arg_list[1]->to_int() - 1;
int corner = arg_list[2]->to_int() - 1;
range_check(face,0,(nspec->GetNumFaces() - 1), GetString(IDS_FACE_INDEX_OUT_OF_RANGE));
range_check(corner,0,(nspec->Face(face).GetDegree() - 1), GetString(IDS_FACE_CORNER_INDEX_OUT_OF_RANGE));
return Integer::intern(nspec->GetNormalIndex(face,corner) + 1);
}
return &undefined;
}
getVertIndex , gets the vert index from the face and corner (1..to facedeg) this is to mimic the editnormals GetVertexID function
[b]usage: <int> getVertIndex <edit_poly_node> <int face> <int corner>[/b]
def_visible_primitive(getVertIndex,"getVertIndex");
Value* getVertIndex_cf(Value **arg_list, int count)
{
check_arg_count(getVertIndex, 3, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, getVertIndex);
int face = arg_list[1]->to_int() - 1;
int corner = arg_list[2]->to_int() - 1;
range_check(face,0,(pmesh->numf - 1), GetString(IDS_FACE_INDEX_OUT_OF_RANGE));
range_check(corner,0,(pmesh->f[face].deg - 1), GetString(IDS_FACE_CORNER_INDEX_OUT_OF_RANGE));
return Integer::intern(pmesh->f[face].vtx[corner] + 1);
}
VertexToSpecNormals , returns a bitarray of normal ids from a vertex id
[b]usage: <bitarray> VertexToSpecNormals <edit_poly_node> <int vertex>
[/b]
def_visible_primitive(VertexToSpecNormals,"VertexToSpecNormals");
Value* VertexToSpecNormals_cf(Value **arg_list, int count)
{
check_arg_count(VertexToSpecNormals, 2, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, VertexToSpecNormals);
// range check
int vert = arg_list[1]->to_int() - 1;
range_check(vert,0,(pmesh->numv - 1), GetString(IDS_VERTEX_INDEX_OUT_OF_RANGE));
MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
if(nspec)
{
// new bitarray to size required
BitArray normals(nspec->GetNumNormals());
normals.ClearAll();
int numfaces = nspec->GetNumFaces();
// make sure we use the max number of faces
if(pmesh->numf < numfaces)
numfaces = pmesh->numf;
// exit if zero
if(!numfaces)
return &undefined;
for (int i=0; i < numfaces; i++)
{
// skip over dead faces
if (pmesh->f[i].GetFlag(MN_DEAD))
continue;
MNNormalFace& face = nspec->Face(i);
int facedeg = face.GetDegree();
// use the max face degree
if(pmesh->f[i].deg < facedeg)
facedeg = pmesh->f[i].deg;
for(int j=0; j < facedeg; j++)
{
// next vert if not ours
if(vert != pmesh->f[i].vtx[j])
continue;
// grab the normal index
int normalID = face.GetNormalID(j);
// check we're in range if not continue
if(normalID < 0 || normalID >= normals.GetSize())
continue;
// save the normal id
normals.Set(normalID);
}
}
return new BitArrayValue(normals);
}
return &undefined;
}
getSpecNormalFaceDeg , gets the normal face degree
[b]usage: <int> getSpecNormalFaceDeg <edit_poly_node> <int face>
[/b]
def_visible_primitive(getSpecNormalFaceDeg,"getSpecNormalFaceDeg");
Value* getSpecNormalFaceDeg_cf(Value **arg_list, int count)
{
check_arg_count(getSpecNormalFaceDeg, 2, count);
MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_BASE_OBJ, NULL, getSpecNormalFaceDeg);
MNNormalSpec* nspec = pmesh->GetSpecifiedNormals();
if(nspec)
{
int face = arg_list[1]->to_int() - 1;
range_check(face,0,(nspec->GetNumFaces() - 1),GetString(IDS_FACE_INDEX_OUT_OF_RANGE));
return Integer::intern(nspec->Face(face).GetDegree());
}
return &undefined;
}
edit: i’ve just noticed i’ve used MESH_BASE_OBJ instead of MESH_READ_ACCESS in functions where they don’t change the mesh. Just means some functionality (working on objects with modifier present) will be lost but it keeps it consistent I suppose.
there are two functions about poly edge loop/ring shift selection… poly has these methods but the difference is mine don’t really need a selection
def_visible_primitive(setSelectionShift, "setSelectionShift");
Value* setSelectionShift_cf(Value** arg_list, int count)
{
check_arg_count(setSelectionShift, 5, count);
INode *node = arg_list[0]->to_node();
int shift = arg_list[1]->to_int();
bool move = (arg_list[2] == &true_value);
bool add = (arg_list[3] == &true_value);
Object* obj = Get_Object_Or_XRef_BaseObject(node->GetObjectRef());
if (obj->ClassID() == EPOLYOBJ_CLASS_ID)
{
BaseInterface* i = ((Animatable*)obj)->GetInterface(EPOLY_INTERFACE);
if (i)
{
EPoly* ip = (EPoly*)i;
if (arg_list[4] == &true_value)
ip->EpfnSetRingShift(shift, move, add);
else
ip->EpfnSetLoopShift(shift, move, add);
node->NotifyDependents(FOREVER, PART_GEOM | PART_TOPO | PART_SELECT, REFMSG_CHANGE);
node->NotifyDependents(FOREVER,0,REFMSG_SUBANIM_STRUCTURE_CHANGED);
ip->RefreshScreen();
return &true_value;
}
return &false_value;
}
return &undefined;
}
def_visible_primitive(getEdgeSelectionShift, "getEdgeSelectionShift");
Value* getEdgeSelectionShift_cf(Value** arg_list, int count)
{
check_arg_count_with_keys(getEdgeSelectionShift, 2, count);
INode *node = arg_list[0]->to_node();
int value = arg_list[1]->to_int();
Value* tmp;
BOOL loop = bool_key_arg(loop, tmp, TRUE);
Object* obj = Get_Object_Or_XRef_BaseObject(node->GetObjectRef());
if (obj->ClassID() == EPOLYOBJ_CLASS_ID)
{
BitArray newSel;
PolyObject *poly = dynamic_cast<PolyObject *>(obj);
if(poly && poly->GetMesh().nume > 0)
{
MNMesh &mesh = poly->GetMesh();
newSel.SetSize(mesh.nume);
newSel.ClearAll();
IMNMeshUtilities8* meshToShift = static_cast<IMNMeshUtilities8*>(mesh.GetInterface( IMNMESHUTILITIES8_INTERFACE_ID ));
if (loop)
{
meshToShift->SelectEdgeLoopShift(value,newSel);
//mprintf("loop: %f
", dir);
}
else meshToShift->SelectEdgeRingShift(value,newSel);
}
return new BitArrayValue(newSel);
}
return &undefined;
}
and it works for Editable poly base object. so i use it for example for skin step loop/ring