Notifications
Clear all

[Closed] A way to drag and drop materials outside the MatEd

I’ve been working on a script to manage materials (thread here: http://forums.cgsociety.org/showthread.php?f=98&t=629065 ) and I was constantly annoyed by the impossibility of assigning a material to an object by drag and drop while outside the Material Editor.

However I think I might have come up with a way to work around this limitation. Here’s the basic idea:

-You start by dragging from somewhere, in my case a node in a .net treeView. As the dragging starts you store the material you are going to apply to the object in a variable (the material is of course selected based on which node is dragged).

-When the mouse leaves the treeView a onMouseLeave event is triggered, which then triggers a mouse tool.

-The mouse tool waits for the user to un-click the mouse button and when this happens, looks for the object under the mouse and then applies to it the material that was previously stored.

This is of course a lot more complicated than it sounds. For example there is no event in a mouse tool to detect that the left mouse button has gone up. My first attempt here was to use the ON freeMove event and continously check the mouse button state. This failed miserably as the mouse.buttonStates property only detects key changes made inside the viewport and thus failed to realize that the left mouse button was allready pressed when the cursor entred the viewport.

Currently I have fixed this using some .NET to check the mouse button state. While not really perfect, as the user has to move the mouse AFTER the button has been released for the event to launch, it is certanly a step in the right direction.

If anyone is interested I’ll try to come up with a code example (right now it’s too tangled with the script to be easy to understand).

8 Replies

hi marco, i have detailed how to do this on my website.

http://www.lonerobot.com/FileDrop.html

There is a sample you can download. I have done this on a label control in the example but it can be used on any control that supports drag and drop. Max handles the code you drop internally, depend on the string type you drop, if its an image it allows you to crreate a material. this works with dropping to viewport nodes and to slots in the MatEd.

This is very interesting, I wish I had found it a few months ago.

However it’s not exactly what I’m doing; your method, while a lot cleaner probably, is limited to drag and dropping files. And what I’m doing is drag and dropping a whole material, that is to say mimicking the way you normally drag and drop a material from the material editor to the scene. This would be impossible with your system as a material can not be referenced by a string filename.

But like I said, I can probably refine the code I’ve already done looking at your example, so thanks!

hi marco,

i’m glad it partially hepled. You are right, a material is not just a string filename – except if it is a simple standard material with the map in the diffuse channel that you are wanting, as this is how max handles the filename string. If you drop this onto an object, it creates a standard diffuse material, into the viewport it asks if you want to apply as an environment map/viewport background. The drop event in max seems to check for the filetype on drop and present you with the options befitting the filetype, according to what i can make out from the SDK.

I am thinking there might be a way of doing this with an entire material, as essentialy a succesful drag drop event could be used to trigger the material change. The dataobject itself could even contain dummy infomation, but use the event itself to set the material. I will try and look into this a bit as well as I think it would be a useful thing. I would like to be able to drag and drop a targa file onto an object and have it create an A&D material with the targa mask as a cutout channel for example.

But dude, I already made it work! That was the point of my first post. It’s slightly buggy since I did not have time to properly debug it yet but the method I explained works. I am now capable(ish) of drag and dropping materials wherever I want! THE SKY IS THE LIMIT!

Or something…

as this thread was referenced from another ( http://forums.cgsociety.org/showthread.php?p=5753016#post5753016 )

How do the methods described here apply to, for example, drag and drop a material from the material editor to a control in a maxscript / .net dialog?

Well there is no onMouseLeave event or similar for the material editor so my method is probably a no go.

However there’s only a few MatEd slots, so I would probably just have a way to import the desidered material directly from the script / .net dialog… maybe a right click menu of sorts? Of course it dependes on the script itself.

Shouldn’t you be able to do it using LoneRobots string method? Since material names stored in Max scenes are typically unique strings, you could just pass the string to the control object, and when the string is dropped on a Medit slot, or object, just call the name from the scenematerials array. In theory that is, don’t have time to test now.

-Eric

Here’s a more elegant way I’ve found to do this:

fn hitTest =
  --Returns the object at the mouse position in the viewport	
  (
  	local theRay=mapScreenToWorldRay mouse.pos
  	local dist=undefined
  	local theHit=undefined
  	local hitObject=undefined
  	for x in objects do 
  	(
  		hitRay=intersectRay x theRay
  		if hitRay!=undefined then
  		(
  			tempDist=distance hitRay.pos theRay.pos
  			if dist==undefined or tempDist<dist then
  			(
  				dist=tempDist
  				theHit=hitRay
  				hitObject = X
  			)
  		)
  	)
  	hitObject 
  )
  
  rollout testRoll "Drag Test"
  (
  	local theMat --Stores the material to apply to the object
  	local theObject --Stores the object who's material you are aobut to change
  	local dragFlag = false --A flag to keep the material from beeing changed if the drag and drop did not end outside the treeView and the rollout looses focus
  	dotNetControl matTreeView "TreeView" height:477 width:150 pos:[9,26]
  	
  	ON matTreeView ItemDrag arg DO
  	--When the dragging starts store the corresponding material
  	(
  		dragFlag = true
  		theMat = (getMeditMaterial (arg.item.index+1))
  	)
  	
  	ON matTreeView mouseUp arg DO
  	--Then the mouse button is up set the flag to false. Only happens if the mouse button is released INSIDE the treeView
  	(
  		dragFlag = false
  	)
  	
  	ON matTreeView lostFocus arg DO
  	--When the treeview looses focus find the object under the mouse and apply the material
  	(
  		theObject = hitTest()
  		IF theObject != undefined AND dragFlag == true DO --Check an object was found and that the flag is set to true
  		(
  			theObject.material = theMat
  		)
  		theObject = undefined
  	)
  
  	ON testRoll OPEN DO
  	--When the roll open populate with the materials in the MatEd
  	(
  		FOR mat = 1 to 24 DO
  		(
  			matTreeView.nodes.Add (getmeditMaterial mat).name
  		)
  		matTreeView.allowDrop = true
  	)
  )
  
  createDialog testRoll

The secret for this one is the “lostFocus” event in the treeView. This only fires when the treeView looses focus, and if a drag and drop has been started this only happens once the user RELEASES the mouse button. Add a couple of touches here and there and you get a pretty nice simulation of a material drag and drop. Check the code for more details.

NOTE: the hitTes() function is not mine… I think I found it on these forums somewhere… not sure who wrote it.