{"id":3897,"date":"2010-12-01T05:18:05","date_gmt":"2010-12-01T05:18:05","guid":{"rendered":"http:\/\/www.mrbluesummers.com\/?p=3897"},"modified":"2012-02-21T17:58:06","modified_gmt":"2012-02-21T17:58:06","slug":"how-to-deploy-maxscript-scripts","status":"publish","type":"post","link":"http:\/\/www.mrbluesummers.com\/3897\/3d-tutorials\/how-to-deploy-maxscript-scripts","title":{"rendered":"How to Deploy MaxScript Scripts"},"content":{"rendered":"
You’ve spent a lot of time putting together a useful MaxScript and you want the whole world to enjoy it! \u00a0Unfortunately, you’re not sure of the best way to get it into the hands of the people. \u00a0Luckily, MaxScript comes with three major techniques for deploying a script and we’re going to cover them today. \u00a0These three techniques are<\/p>\n
We’ll be going through these examples with a simple “Select Non-Quad Polygons” script from the MaxScript documentation.<\/p>\n
The first way is best for beginners and involves coding up a script that executes in a single go. \u00a0The script below operates in that way. \u00a0It iterates across all faces in the object to select non-quadrilateral faces. \u00a0Note that this script only works for editable poly objects and will throw an error for anything else!<\/p>\n
local face_selection = #{}\r\nlocal base_obj = $.baseobject\r\nlocal num_faces = polyop.getNumFaces base_obj\r\nfor f = 1 to num_faces do\r\n(\r\n\tlocal num_face_verts = polyop.getFaceDeg base_obj f\r\n\tif num_face_verts != 4 do face_selection[f] = true\r\n)--end f loop\r\npolyop.setFaceSelection base_obj face_selection\r\nmax modify mode\r\nmodPanel.setCurrentObject base_obj\r\nsubobjectlevel = 4<\/pre>\nIn this case, when the script is run, the faces are selected and the user is unceremoniously dropped off at the object’s “Polygon Select” level. \u00a0For a script with this level of involvement, this is an appropriate deployment mechanism. \u00a0The user just runs the script whenever they need it. \u00a0The script usually sits in a folder somewhere waiting for the user to invoke it.<\/p>\n
Method 2- Macroscript (With optional auto-deploy)<\/h2>\n
A Macroscript is a wrapper that goes around your entire script and allows it to be bound to a hotkey or made a UI item. \u00a0This deployment method is good for intermediate users and for larger scripts that are a little more involved. \u00a0Let’s try wrapping the script above into a Macroscript and see it in the 3ds Max user interface.<\/p>\n
macroscript SelectNonQuadPolys category:\"Bluesummers\" \\\r\ntooltip:\"Select Non-Quads\"\r\n(\r\n\ton isEnabled return\r\n\t(\r\n\t\tselection.count == 1 and classOf selection[1].baseobject == Editable_Poly\r\n\t)\r\n\ton execute do\r\n\t(\r\n\t\tlocal face_selection = #{}\r\n\t\tlocal base_obj = $.baseobject\r\n\t\tlocal num_faces = polyop.getNumFaces base_obj\r\n\t\tfor f = 1 to num_faces do\r\n\t\t(\r\n\t\t\tlocal num_face_verts = polyop.getFaceDeg base_obj f\r\n\t\t\tif num_face_verts != 4 do face_selection[f] = true\r\n\t\t)--end f loop\r\n\t\tpolyop.setFaceSelection base_obj face_selection\r\n\t\tmax modify mode\r\n\t\tmodPanel.setCurrentObject base_obj\r\n\t\tsubobjectlevel = 4\r\n\t)--end on execute\r\n)--end script<\/pre>\nNotice that in this case we’ve added two important elements. The first is a check to make sure we have an editable_poly object selected. \u00a0The second is the Macroscript<\/strong> wrapper that allows this tool to become part of the user interface. It has a name, a tooltip, a category, and can even take on a standard or custom icon (see MaxScript documentation). If you execute the script above and then go to “Customize > Customize User Interface” and select the “Bluesummers” Category, you’ll see the script appear. \u00a0You can bind it to a hotkey or add it to a Quad Menu or rollout floater.<\/p>\n
In order to deploy this kind of script, you’ll need to have the user drop it into their “StdScripts” folder of their 3d Studio Max installation. \u00a0This is no fun since it adds some complexity. \u00a0For most 3dsMax installations, that folder is<\/p>\n
C:\\Program Files\\Autodesk\\3ds Max 2009\\stdplugs\\stdscripts<\/pre>\nAny scripts in this folder will be run during 3dsMax’s startup process, and when you have the Macroscript wrapper around your script then you’re effectively “registering” a new tool during startup.<\/p>\n
You can get pretty creative during this process. For example, during startup you can register the Macroscript into the user’s interface which basically “installs” it into 3d Studio Max. Consider the following snippet from my WedTexVerts script that installs it into the 3d Studio Max UnwrapUVWs modifier UI automatically.<\/p>\n
Macroscript <...>\r\n(\r\n\t<...shortened...>\r\n)\r\n-- If the registration fails, that means it's already there.\r\nif menuMan.registerMenuContext 0x1c413679 do\r\n(\r\n\tlocal ToolsMenuIndex, ToolsMenuItem\r\n\tlocal ToolsMenu, WeldVertTool, UVW_MenuBar\r\n\r\n\t-- Get the main UVW menu bar\r\n\tUVW_MenuBar = MenuMan.getMenu 128 \r\n\r\n\t-- The above is not always true. Let's check to make\r\n\t-- sure so we don't totally wreck the UI\r\n\tif UVW_MenuBar.getTitle() != \"UVW Unwrap - Menu Bar\"\r\n\tdo throw \"Critical Error: Your UI Could not be modified \\\r\n\t\t\t\tbecause you have made changes to your .mnu \\\r\n\t\t\t\tfile.\"\r\n\r\n\t-- Get the tools index. Should be 4th from the left.\r\n\t-- Double check the title to make sure.\r\n\tfor i = 1 to UVW_MenuBar.numItems() do\r\n\t\tif (UVW_MenuBar.getItem i).getTitle() == \"Tools\" do\r\n\t\t\tToolsMenuIndex = i\r\n\r\n\t-- Get the menu item that holds the help menu\r\n\tToolsMenuItem = UVW_MenuBar.getItem(ToolsMenuIndex)\r\n\r\n\t-- Get the menu from the item\r\n\tToolsMenu = ToolsMenuItem.getSubMenu()\r\n\r\n\t-- Create a menu item that calls the WeldTexvert Tool.\r\n\tWeldVertTool = (menuMan.createActionItem \"WeldSelectedFloater\" \"Bluesummers' Tools\")\r\n\r\n\t-- Add the action item to the end of the help menu.\r\n\tToolsMenu.addItem WeldVertTool 7\r\n\r\n\t-- redraw the menu bar with the new item\r\n\tMenuMan.updateMenuBar()\r\n)<\/pre>\nThis is a pretty complicated process, so I’ll leave it to you to read more about the MaxScript MenuMan <\/strong>object. You should just be aware that your users may not always be smart enough to bind up your tools to a hotkey and you can take the liberty of putting your new functionality directly into their interface. \u00a0However, you should also\u00a0be extremely careful as the smallest mistake could damage the user’s interface<\/span>.<\/p>\n
Method 3- Scripted Plug-Ins<\/h2>\n
Finally, it’s possible for us to deploy scripted plug-ins. These tend to be the largest scripts of all and are basically full extensions of 3dsMax functionality. You can create render filters, meshes, modifiers, and more. You’ll basically deploy your script similarly to a Macroscript- by having your user insert the script into their 3dsMax C:\/…\/stdscripts\/ folder. However, instead of wrapping your functionality in a Macroscript, you’ll wrap it in a scripted plug-in context.<\/p>\n
Take a look at the code below, where the script creates a new object type called a Cuboid.<\/p>\n
plugin geometry Cuboid\r\nname:\"Cuboid\"\r\nclassID:#(0x133077, 0x54375)\r\ncategory:\"Scripted Primitives\"\r\nextends:Box\r\n(\r\n\tfn fmax val1 val2 = if val1 > val2 then val1 else val2\r\n\ttool create\r\n\t(\r\n\t\ton mousePoint click do\r\n\t\tcase click of\r\n\t\t(\r\n\t\t\t1: nodeTM.translation = gridPoint\r\n\t\t\t2: #stop\r\n\t\t)\r\n\r\n\t\ton mouseMove click do\r\n\t\t\tif click == 2 then\r\n\t\t\t\tdelegate.width = delegate.length = delegate.height = \\\r\n\t\t\t\t2 * fmax (abs gridDist.x) (abs gridDist.y)\r\n\t)\r\n)<\/pre>\nGranted this procedure takes significantly more work than the other two options, it does integrate your tools more deeply into 3d Studio Max and can be quite useful for circumstances where you want to create a “normal” extension of the tools available.<\/p>\n
And there you have it! \u00a0Those are three awesome ways to deploy your scripts to anyone who needs them. \u00a0Happy coding!<\/p>\n","protected":false},"excerpt":{"rendered":"
You’ve spent a lot of time putting together a useful MaxScript and you want the whole world to enjoy it! \u00a0Unfortunately, you’re not sure of the best way to get it into the hands of the people. \u00a0Luckily, MaxScript comes with three major techniques for deploying a script and we’re going to cover them today. […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,16],"tags":[2513,214,2508,2512],"_links":{"self":[{"href":"http:\/\/www.mrbluesummers.com\/wp-json\/wp\/v2\/posts\/3897"}],"collection":[{"href":"http:\/\/www.mrbluesummers.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.mrbluesummers.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.mrbluesummers.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.mrbluesummers.com\/wp-json\/wp\/v2\/comments?post=3897"}],"version-history":[{"count":0,"href":"http:\/\/www.mrbluesummers.com\/wp-json\/wp\/v2\/posts\/3897\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.mrbluesummers.com\/wp-json\/wp\/v2\/media?parent=3897"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.mrbluesummers.com\/wp-json\/wp\/v2\/categories?post=3897"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.mrbluesummers.com\/wp-json\/wp\/v2\/tags?post=3897"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}