Created
November 21, 2023 12:46
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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 ""</list> | |
<list type="Node">1 itemtype 0 1 "py.delete.vmap"</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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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