Mesh
Explode EditPoly
fn explodeEPoly obj =
(
-- Storing frequently used functions in user variables for faster access
local getNumFaces = polyOp.getNumFaces
local getElementsUsingFace = polyOp.getElementsUsingFace
local detachFaces = polyOp.detachFaces
if getNumFaces obj > 0 then
(
local element = getElementsUsingFace obj 1
while element.numberset < (getNumFaces obj) do
(
detachFaces obj element asNode:true
element = getElementsUsingFace obj 1
)
)
)
explodeEPoly $
User Interface
Open File Dialog Multiselect
fn openFileDialog title:"Open File" filter:"All Files|*.*" multiselect:false =
(
local dialog = dotnetobject "System.Windows.Forms.OpenFileDialog"
dialog.title = title
dialog.filter = filter
dialog.multiselect = multiselect
local result = undefined
if (dialog.showDialog() == (dotnetclass "System.Windows.Forms.DialogResult").Ok) then
(
if multiselect then
result = dialog.filenames
else
result = dialog.filename
)
dialog.dispose()
return result
)
openFileDialog multiselect:true
Advanced Message Box
fn MessageBoxEx message caption:"Message" buttons:#OK icon:#Information =
(
local MsgBox = dotnetclass "System.Windows.Forms.MessageBox"
local MessageBoxButtons = dotnetclass "System.Windows.Forms.MessageBoxButtons"
local MessageBoxIcon = dotnetclass "System.Windows.Forms.MessageBoxIcon"
local DialogResult = dotnetclass "System.Windows.Forms.DialogResult"
local _buttons = case buttons of
(
#AbortRetryIgnore: MessageBoxButtons.AbortRetryIgnore
#OK: MessageBoxButtons.OK
#OKCancel: MessageBoxButtons.OKCancel
#RetryCancel: MessageBoxButtons.RetryCancel
#YesNo: MessageBoxButtons.YesNo
#YesNoCancel: MessageBoxButtons.YesNoCancel
)
local _icon = case icon of
(
#Asterisk: MessageBoxIcon.Asterisk
#Error: MessageBoxIcon.Error
#Exclamation: MessageBoxIcon.Exclamation
#Hand: MessageBoxIcon.Hand
#Information: MessageBoxIcon.Information
#None: MessageBoxIcon.None
#Question: MessageBoxIcon.Question
#Stop: MessageBoxIcon.Stop
#Warning: MessageBoxIcon.Warning
)
local result = case MsgBox.Show message caption _buttons _icon of
(
(DialogResult.Abort): #Abort
(DialogResult.Cancel): #Cancel
(DialogResult.Ignore): #Ignore
(DialogResult.No): #No
(DialogResult.None): #None
(DialogResult.OK): #OK
(DialogResult.Retry): #Retry
(DialogResult.Yes): #Yes
)
return result
)
MessageBoxEx "Some text"
Custom Picker Dialog
fn numberPicker =
(
rollout picker "Number Picker" width:160
(
local result
spinner spnValue "Value:" width:126 align:#center
button btnOk "Ok" width:60 align:#center across:2
button btnCancel "Cancel" width:60 align:#center
on btnOk pressed do
(
result = spnValue.value
destroyDialog picker
)
on btnCancel pressed do
destroyDialog picker;
)
createDialog picker modal:true
return picker.result
)
print (numberPicker())
SubAnim Picker
(
local ContextMenuStrip = dotnetclass "System.Windows.Forms.ContextMenuStrip"
local ToolStripMenuItem = dotnetclass "System.Windows.Forms.ToolStripMenuItem"
local _contextMenuStrip
local _pickSubAnimCallback
fn ToolStripMenuItem_Click s e =
(
_pickSubAnimCallback s.Tag.Value
if s.HasDropDownItems then
_contextMenuStrip.Close()
)
fn subAnimsToMenuItem subanim =
(
local item = dotnetobject ToolStripMenuItem subanim.name
item.Tag = dotnetmxsvalue subanim
if subanim.numSubs > 0 then
(
item.DoubleClickEnabled = true
dotnet.addEventHandler item "DoubleClick" ToolStripMenuItem_Click
for i = 1 to subanim.numSubs do
(
local subitem = subAnimsToMenuItem subanim[i]
item.DropDownItems.Add subitem
)
)
else dotnet.addEventHandler item "Click" ToolStripMenuItem_Click;
return item
)
fn applyFilter menuitem filter =
(
if menuitem.HasDropDownItems then
(
local hasAvailableItems = false
for i = 0 to menuitem.DropDownItems.Count - 1 do
(
applyFilter menuitem.DropDownItems.Item[i] filter
if not hasAvailableItems then
hasAvailableItems = menuitem.DropDownItems.Item[i].Available
)
menuitem.Available = hasAvailableItems
menuitem.DoubleClickEnabled = filter menuitem.Tag.Value
)
else menuitem.Available = filter menuitem.Tag.Value
)
fn pickSubAnim maxwrapperobj callback filter:unsupplied =
(
local isMaxWrapper = iskindof maxwrapperobj maxwrapper
local isMaxScriptFunction = classof callback == maxscriptfunction
if isMaxWrapper and isMaxScriptFunction then
(
_contextMenuStrip = dotnetobject ContextMenuStrip
_pickSubAnimCallback = callback
for i = 1 to maxwrapperobj.numsubs do
_contextMenuStrip.Items.Add (subAnimsToMenuItem maxwrapperobj[i])
if filter != unsupplied then
for i = 0 to _contextMenuStrip.Items.Count - 1 do
applyFilter _contextMenuStrip.Items.Item[i] filter
_contextMenuStrip.Show mouse.screenpos.x mouse.screenpos.y
)
)
/* How to use */
fn pickCallback subanim =
print subanim;
fn subAnimFilter subanim =
return subanim.value != undefined;
pickSubAnim $ pickCallback filter:subAnimFilter
)
Array
Shuffle
fn shuffle arr =
(
local num = arr.count
local j
for i = 1 to num do
(
j = random 1 num
swap arr[i] arr[j]
)
return arr
)
String
Regex Substitution
fn gsub string pattern evaluator =
(
global __RegexMatch
if __RegexMatch == undefined then
__RegexMatch = (dotnetclass "System.Text.RegularExpressions.Regex").Match;
local match = __RegexMatch string pattern
local result
local pos = 1
if match.Success then
(
local stream = stringstream ""
while match.Success do
(
append stream (substring string pos (match.Index + 1 - pos))
append stream (evaluator match)
pos = match.Index + match.Length + 1
match = match.NextMatch()
)
if pos < string.count then
append stream (substring string pos -1);
result = stream as ::string
free stream
)
else result = copy string
return result
)
-- Finding and replacing integer decimal numbers with hexadecimal
fn eval match =
return "0x" + bit.intAsHex (match.Value as integer);
gsub "5 a 200 b 500 c" @"\d+" eval
-- 0x5 a 0xc8 b 0x1f4 c
Formatted Print
fn printf str args =
(
global __printfMatches
if __printfMatches == undefined then
(
local pattern = @"%([-+#0 ]*\d*(?:\.\d+)?(?:l|l32|l64)?[dioucxXeEfgGs])"
__printfMatches = (dotnetobject "System.Text.RegularExpressions.Regex" pattern).Matches;
)
local matches = __printfMatches str
local output = stringstream ""
local pos = 1
for i = 1 to matches.count do
(
local m = matches.Item[i - 1]
local g = m.Groups.Item[1]
local type = m.Groups.item["type"].Value
append output (substring str pos (m.Index + 1 - pos))
append output (formattedprint args[i] format:g.Value)
pos = m.Index + 1 + m.Length
)
append output (substring str pos (str.count - pos))
return output as string
)
printf "%.5f %s %x %c" #(1.234, "maxscript", 1000, 97)
-- "1.23400 maxscript 3e8 a"
Bitmap
Line Drawing
fn drawLine bmp x0 y0 x1 y1 color:white =
(
local dx = x1 - x0
local dy = y1 - y0
local col = #(color)
if abs dx > abs dy then
(
local step = dy / float dx
for x = x0 to x1 by (if dx > 0 then 1 else -1) do
setPixels bmp [x, y0 + step * (x - x0) + 0.5] col;
)
else
(
local step = dx / float dy
for y = y0 to y1 by (if dy > 0 then 1 else -1) do
setPixels bmp [x0 + step * (y - y0) + 0.5, y] col;
)
)
(
local bmp = bitmap 500 500 color:black
for i = 1 to 120 do
(
local x1 = random 0 500
local y1 = random 0 500
local x2 = random 0 500
local y2 = random 0 500
local col = random black white
drawLine bmp x1 y1 x2 y2 color:col
)
display bmp
)
Color
Color To Integer
fn colorToInt color =
return (bit.shift (integer color.r) 16) + (bit.shift (integer color.g) 8) + integer color.b;
fn intToColor integer =
return color \
(bit.and (bit.shift integer -16) 255) \
(bit.and (bit.shift integer -8) 255) \
(bit.and integer 255);
Viewport
Material Display (Display Filter Fix)
fn restoreMaterialDisplay =
(
-- 0x00000241 - REFMSG_NODE_DISPLAY_PROP_CHANGED - maxsdk\include\ref.h
for i in objects where not i.ishiddenInVpt do
notifyDependents i partID:#display msg:0x00000241;
)
callbacks.addScript #customDisplayFilterChanged "restoreMaterialDisplay()" id:#restoreMaterialDisplay