View Full Version : A way to drag and drop materials outside the MatEd


MarcoBrunetta
10 October 2008, 11:27 PM
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).

LoneRobot
10 October 2008, 08:25 AM
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.

MarcoBrunetta
10 October 2008, 02:23 PM
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!

LoneRobot
10 October 2008, 03:10 PM
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.

MarcoBrunetta
10 October 2008, 05:33 PM
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...

ZeBoxx2
03 March 2009, 08:34 PM
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?

MarcoBrunetta
03 March 2009, 08:55 PM
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.

PiXeL_MoNKeY
03 March 2009, 09:14 PM
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

MarcoBrunetta
04 April 2009, 08:00 PM
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.

CGTalk Moderation
04 April 2009, 08:00 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.


1