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
Old 02 February 2013   #31
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_STRUCTUR  E_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\n", 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
 
Old 02 February 2013   #32
I do find it very odd that those normal functions are not in polyops and meshops !? Oh I like those and have a application for them

also you should probably rename VertexToSpecNormals to getNormalsUsingVert (makes it more mxs like) to late for me as I'm to lazy to change the calling scripts

Last edited by Klunk : 02 February 2013 at 03:44 PM.
 
Old 02 February 2013   #33
I'm intrigued by these functions, how do you actually get these set up with max?

Do you need to compile a DLX file?
__________________
Maxscript Made Easy...
http://davewortley.wordpress.com/
 
Old 02 February 2013   #34
yep, with ms visual studio (version dependent on the target version of max) and the sdk, which is somewhere on your max install disks. My experience of it is, and peoples reluctance to use it is not using the sdk (though the reference is sketchy at best) is getting to grips with creating the initial project in ms visual studio, the stream of errors that can run down the output window when you get it wrong can seem very daunting and ms dev speech is something to behold . But Once up and running though in the case of most of these functions its a case of cut, paste, compile and run.

there is a free book on the subject

Last edited by Klunk : 02 February 2013 at 06:10 PM.
 
Old 02 February 2013   #35
If these are all so useful is it worth lobbying Autodesk to include them in the next 3dsmax build? Surely you've done all the hard work for them?
__________________
Maxscript Made Easy...
http://davewortley.wordpress.com/
 
Old 02 February 2013   #36
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.....


I really wish I could post some useful functions like you guys but I hadn't had to deal with that kind of geometry stuff.

Thanks for sharing, btw.
I am sure it will be useful one day...
 
Old 02 February 2013   #37
I really wish I could post some useful functions like you guys but I hadn't had to deal with that kind of geometry stuff.


I wouldn't worry we're not that fussy
 
Old 02 February 2013   #38
from the slow rollout drawing thread these can turn off redraw while adding rollouts then force a redraw when complete. Gets rid of the annoying flicker with large and complex gui.

// usage: <bool> SetWindowRedraw <HWND>window <bool>

def_visible_primitive(SetWindowRedraw, "SetWindowRedraw");
   
   Value* SetWindowRedraw_cf(Value **arg_list, int count)
   {
   	check_arg_count(SetWindowRedraw, 2, count);
   	HWND hWnd = (HWND)arg_list[0]->to_int();
   	bool redraw = arg_list[1]->to_bool();
   
   	LRESULT res = SendMessage( hWnd , WM_SETREDRAW, redraw, 0);
   	return bool_result(res);
   }


// usage: <bool> RedrawWindow <HWND>window

def_visible_primitive(RedrawWindow, "RedrawWindow");
   
   Value* RedrawWindow_cf(Value **arg_list, int count)
   {
   	check_arg_count(RedrawWindow, 1, count);
   	HWND hWnd = (HWND)arg_list[0]->to_int();
   
   	LRESULT lres = SendMessage( hWnd , WM_SETREDRAW, true, 0);
   	BOOL res = RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
   	return bool_result(lres);
   }


window handle can be accessed with something like

hwnd = (windows.getchildhwnd 0 myrollout.title)[1]



there is probably a better way to get the current dialog handle in the sdk but I to lazy too look ! again thanks to Denis for pointing me in the right direction ( I really should learn more about the windows api )

Last edited by Klunk : 02 February 2013 at 08:31 PM.
 
Old 02 February 2013   #39
Originally Posted by Klunk: window handle can be accessed with something like

hwnd = (windows.getchildhwnd 0 myrollout.title)[1]



there is probably a better way to get the current dialog handle in the sdk but I to lazy too look ! again thanks to Denis for pointing me in the right direction ( I really should learn more about the windows api )


def_visible_primitive(getDialogHWND, "getDialogHWND");
Value* getDialogHWND_cf(Value **arg_list, int count)
{
	check_arg_count(getDialogHWND, 1, count);
	if (is_rollout(arg_list[0])) 
	{
		HWND hwnd = ((Rollout*)arg_list[0])->page;
		return IntegerPtr::intern((INT_PTR)hwnd);
	}
	if (is_rolloutfloater(arg_list[0]))
	{
		HWND hwnd = ((RolloutFloater*)arg_list[0])->window;
		return IntegerPtr::intern((INT_PTR)hwnd);
	}	
	return &undefined;
}
 
Old 02 February 2013   #40
sweet, I'm absolutely staggered at the visual improvement these 3 tiny functions make ! Also useful for getting rid of the flicker when setting gui items to disabled on a selection change or in a selection change handler (which has irritated me for years)

Last edited by Klunk : 02 February 2013 at 12:42 PM.
 
Old 02 February 2013   #41
following on from the quadifier challenge I ported my mxs function to the sdk, very quick now.


returns a bitarray of edges that if removed would create quads, the routine respects material
boundaries and the mesh topology <topo_tolerance> 1.0 faces must be planar 0.0 any ol' face
will do. The quads edges are selected on how "square" the quads are using <quad_tolerance>
(0.0 being perfect 1.0 allows parallel edges) there is an issue where it cannot tell the difference
between concave and convex polys though

<bitarray> QuadifyEdges <poly> <quad_tolerance> <topo_tolerance>


 
  def_visible_primitive(QuadifyEdges,"QuadifyEdges");
  
  Value* QuadifyEdges_cf(Value** arg_list, int count)
  {
      check_arg_count(QuadifyEdges, 3, count);
      MNMesh* pmesh = get_polyForValue(arg_list[0], MESH_READ_ACCESS, NULL, QuadifyEdges);
      float quad_tolerance = arg_list[1]->to_float();
      float topo_tolerance = arg_list[2]->to_float();
  
      int numedges = pmesh->nume;
  
      BitArray edges(numedges);
      edges.ClearAll();
  
      for(int i = 0; i < numedges ;i++)
      {
          MNEdge* edge = pmesh->E(i);
  
          if(edge->GetFlag(MN_DEAD)) 
              continue;
  
          if(edge->f2 == -1)
              continue;
  
          MNFace* f1 = pmesh->F(edge->f1);
          MNFace* f2 = pmesh->F(edge->f2);
          float edgeAngle = pmesh->GetFaceNormal(edge->f1,true) % pmesh->GetFaceNormal(edge->f2,true);
  
          if(f1->deg == 3 && f2->deg == 3 && f1->material == f2->material && edgeAngle > topo_tolerance)
          {
  // collect the edges that make up the prospective quad
  
              int v1e1 = -1;    // v1 f1 edge but not the current edge
              for(int j = 0; j < 3; j++)
              {
                  if(f1->edg[j] == i) continue; 
                  if(pmesh->E(f1->edg[j])->v1 == edge->v1 || pmesh->E(f1->edg[j])->v2 == edge->v1)
                  {
                      v1e1 = f1->edg[j];
                      break;
                  }
              }
              int v1e2 = -1; // v1 f2 edge but not the current edge
              for(int j = 0; j < 3; j++)
              {
                  if(f2->edg[j] == i) continue; 
                  if(pmesh->E(f2->edg[j])->v1 == edge->v1 || pmesh->E(f2->edg[j])->v2 == edge->v1)
                  {
                      v1e2 = f2->edg[j];
                      break;
                  }
              }
              int v2e1 = -1; // v2 f1 edge but not the current edge
              for(int j = 0; j < 3; j++)
              {
                  if(f1->edg[j] == i) continue; 
                  if(pmesh->E(f1->edg[j])->v1 == edge->v2 || pmesh->E(f1->edg[j])->v2 == edge->v2)
                  {
                      v2e1 = f1->edg[j];
                      break;
                  }
              }
              int v2e2 = -1; // v2 f2 edge but not the current edge
              for(int j = 0; j < 3; j++)
              {
                  if(f2->edg[j] == i) continue; 
                  if(pmesh->E(f2->edg[j])->v1 == edge->v2 || pmesh->E(f2->edg[j])->v2 == edge->v2)
                  {
                      v2e2 = f2->edg[j];
                      break;
                  }
              }
              if( v1e1 == -1 ||  v1e2 == -1 || v2e1 == -1 || v2e2 == -1)
                  continue;  // something wrong to get here :(
  
              Point3 e1dir = (pmesh->v[pmesh->E(v1e1)->v2].p - pmesh->v[pmesh->E(v1e1)->v1].p).FNormalize();
              Point3 e2dir = (pmesh->v[pmesh->E(v1e2)->v2].p - pmesh->v[pmesh->E(v1e2)->v1].p).FNormalize();
              float v1edgeangle = fabs(e1dir % e2dir);
  
              e1dir = (pmesh->v[pmesh->E(v2e1)->v2].p - pmesh->v[pmesh->E(v2e1)->v1].p).FNormalize();
              e2dir = (pmesh->v[pmesh->E(v2e2)->v2].p - pmesh->v[pmesh->E(v2e2)->v1].p).FNormalize();
              float v2edgeangle = fabs(e1dir % e2dir);
  
              if(v1edgeangle < quad_tolerance && v2edgeangle < quad_tolerance)
                  edges.Set(i);
          }
      }
      return new BitArrayValue(edges);
  }

Last edited by Klunk : 02 February 2013 at 04:17 PM.
 
Old 02 February 2013   #42
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....

i'm playing with your set of functions... they are really cool. but i can't figure out why after i change a normal and apply edit_normal modifier to the poly, i see the normal non-set. as i expect the edit_normal modifier has to show how the spec normals currently set in the MNMesh
 
Old 02 February 2013   #43
did you make them specified or explicit after you set it ? I only included functions to zap the lot as I tend to use them as set all at once but should be pretty easy to add the set an individual normal to specified or explicit.
 
Old 02 February 2013   #44
Originally Posted by Klunk: did you make them specified or explicit after you set it ? I only included functions to zap the lot as I tend to use them as set all at once but should be pretty easy to add the set an individual normal to specified or explicit.

setAllSpecNormalsExplicit to ON works...
but any way i have some strange result... check the sample:

  delete objects
  s = sphere()
  addmodifier s (edit_normals())
  converttopoly s
  b = box pos:[40,0,0]
  	
  deleteAllChangeHandlers id:#follow_tm
  when transform b change id:#follow_tm handleAt:#redrawViews obj do
  (
  	for n=1 to getNumSpecNormals s do setSpecNormal s n obj.transform[3]
  	setAllSpecNormalsExplicit s on
  	update s	
  )
  


edit:
it seams like it works as expected... good. i keep playing... thanks

Last edited by denisT : 02 February 2013 at 11:07 PM.
 
Old 02 February 2013   #45
you could use this sort of thing instead of adding the edit normals mod but after converting to editable poly...

if not hasSpecifiedNormals obj then 
     	buildSpecifiedNormals obj;	
   


let me know any strangeness, they seem to be a bit "odd" sometimes but using the reset seems correct any issues (not an issue for my purpose as I'm setting them procedurally most of the time).

Last edited by Klunk : 02 February 2013 at 11:20 PM.
 
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 05:13 PM.


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