Skip to content

Instantly share code, notes, and snippets.

@rondreas
Created November 21, 2023 12:46
Show Gist options
  • Save rondreas/d35fd72293e85aeca89d6c9a71cda98a to your computer and use it in GitHub Desktop.
Save rondreas/d35fd72293e85aeca89d6c9a71cda98a to your computer and use it in GitHub Desktop.
Modo is missing a mesh operator for deleting vertex maps, here it is as a Python plugin
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<atom type="CommandHelp">
<hash type="Item" key="py.delete.vmap@en_US">
<atom type="UserName">Delete Vertex Map</atom>
<hash type="Channel" key="name">
<atom type="UserName">Name</atom>
</hash>
<hash type="Channel" key="type">
<atom type="UserName">Type</atom>
<atom type="ArgumentType">py.delete.vmap.types</atom>
</hash>
</hash>
</atom>
<atom type="Filters">
<hash type="Preset" key="py.delete.vmap:filterPreset">
<atom type="Name">Delete Vertex Map</atom>
<atom type="Description">Delete Vertex Map</atom>
<atom type="Category">pmodel:filterCat</atom>
<atom type="Enable">1</atom>
<list type="Node">1 .group 0 &quot;&quot;</list>
<list type="Node">1 itemtype 0 1 &quot;py.delete.vmap&quot;</list>
<list type="Node">-1 .endgroup </list>
</hash>
</atom>
<atom type="Attributes">
<hash type="Sheet" key="py.delete.vmap:sheet">
<atom type="Label">Delete Vertex Map</atom>
<atom type="Filter">py.delete.vmap:filterPreset</atom>
<hash type="InCategory" key="itemprops:general#head">
<atom type="Ordinal">110</atom>
</hash>
<list type="Control" val="ref item-common:sheet">
<atom type="StartCollapsed">0</atom>
<atom type="Hash">#0</atom>
</list>
<list type="Control" val="ref meshoperation:sheet">
<atom type="StartCollapsed">0</atom>
<atom type="Hash">#1</atom>
</list>
<list type="Control" val="cmd item.channel py.delete.vmap$name ?">
</list>
<list type="Control" val="cmd item.channel py.delete.vmap$type ?">
</list>
</hash>
</atom>
<atom type="Categories">
<hash type="Category" key="MeshOperations">
<hash type="C" key="py.delete.vmap">vertexmap</hash>
</hash>
</atom>
</configuration>
"""
Modo is missing a mesh operation for deleting vertex maps, so this is a working prototype for how one could make it
"""
import lx
import lxifc
SERVER_NAME = "py.delete.vmap"
# not including all vmaps, if other types should be supported one can edit this tuple.
_vmap_types = (
(lx.symbol.i_VMAP_MORPH, 'morph', 'Morph'),
(lx.symbol.i_VMAP_SPOT, 'spot', 'Spot'),
(lx.symbol.i_VMAP_NORMAL, 'normal', 'Normal'),
(lx.symbol.i_VMAP_TEXTUREUV, 'texture', 'Texture'),
(lx.symbol.i_VMAP_WEIGHT, 'weight', 'Weight'),
(lx.symbol.i_VMAP_RGB, 'rgb', 'RGB'),
(lx.symbol.i_VMAP_RGBA, 'rgba', 'RGBA'),
)
class VmapTypesHint(lxifc.UIValueHints):
def uiv_Flags(self):
return lx.symbol.fVALHINT_POPUPS
def uiv_PopCount(self):
return len(_vmap_types)
def uiv_PopInternalName(self, index: int):
return _vmap_types[index][1]
def uiv_PopUserName(self, index: int):
return _vmap_types[index][2]
class Instance(lxifc.PackageInstance):
pass
class Package(lxifc.Package, lxifc.ChannelUI):
def pkg_SetupChannels(self, addChan: lx.object.Unknown):
add_channel = lx.object.AddChannel(addChan)
add_channel.NewChannel('name', lx.symbol.sTYPE_STRING)
add_channel.NewChannel('type', lx.symbol.sTYPE_INTEGER)
add_channel.SetDefault(0.0, 3)
def pkg_TestInterface(self, guid):
return lx.service.GUID().Compare(guid, lx.symbol.u_PACKAGEINSTANCE) == 0
def pkg_Attach(self):
return Instance()
def cui_UIValueHints(self, channel_name):
if channel_name == "type":
return VmapTypesHint()
class MeshOperation(lxifc.MeshOperation):
def __init__(self):
self.name = ""
self.type = 3
def mop_Compare(self, other):
return lx.symbol.iMESHOP_DIFFERENT
def mop_Convert(self, other):
return lx.result.OK
def mop_Evaluate(self, mesh, type, mode):
mesh = lx.object.Mesh(mesh)
if not mesh.test():
return
# attempt getting the vertex map, or exit early if it's "null"
vmap = mesh.MeshMapAccessor()
if not vmap.test():
return
# attempt a lookup for the user supplied name and type, if it does not exist there is nothing for us to delete.
try:
vmap.SelectByName(self.type, self.name)
except LookupError:
return
vmap.Remove()
mesh.SetMeshEdits(lx.symbol.f_MESHEDIT_GEOMETRY)
class Modifier(lxifc.Modifier):
def __init__(self, item, evaluation):
evaluation = lx.object.Evaluation(evaluation)
self.attr = lx.object.Attributes(evaluation)
item = lx.object.Item(item)
if not item.test():
return
self.name_index = evaluation.AddChannelName(item, "name", lx.symbol.fECHAN_READ)
self.type_index = evaluation.AddChannelName(item, "type", lx.symbol.fECHAN_READ)
self._output_index = evaluation.AddChannelName(item, lx.symbol.sICHAN_MESHOP_OBJ, lx.symbol.fECHAN_WRITE)
def mod_Test(self, item, index):
item = lx.object.Item(item)
if not item.test():
return False
def mod_Evaluate(self):
mesh_operation = MeshOperation()
mesh_operation.name = self.attr.GetString(self.name_index)
# get the index for our enumerated vmap types into an actual vmap type value.
itype = self.attr.GetInt(self.type_index)
mesh_operation.type = _vmap_types[itype][0]
value_reference = lx.object.ValueReference(self.attr.Value(self._output_index, 1))
value_reference.SetObject(mesh_operation)
class EvalModifier(lxifc.EvalModifier):
def __init__(self):
self.itemType = lx.service.Scene().ItemTypeLookup(SERVER_NAME)
self.scene = lx.object.Scene()
self.index = 0
self.count = 0
def eval_Reset(self, scene):
self.scene = lx.object.Scene(scene)
self.index = 0
self.count = self.scene.ItemCount(self.itemType)
def eval_Next(self):
if self.index >= self.count:
return 0, 0
item = self.scene.ItemByIndex(self.itemType, self.index)
self.index += 1
return item, 0
def eval_Alloc(self, item, index, evaluation):
return Modifier(item, evaluation)
tags = {lx.symbol.sMOD_TYPELIST: SERVER_NAME}
lx.bless(EvalModifier, SERVER_NAME + ".mod", tags)
tags = {
lx.symbol.sPKG_SUPERTYPE: lx.symbol.sITYPE_MESHOP,
lx.symbol.sPMODEL_SELECTIONTYPES: lx.symbol.sSELOP_TYPE_NONE,
lx.symbol.sPMODEL_NOTRANSFORM: "."
}
lx.bless(Package, SERVER_NAME, tags)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment