Last active
May 31, 2016 16:29
-
-
Save Farfarer/cae8f6bdf4856ecb0cf85dc484a2dfb3 to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env python | |
# Transfer the selected weight maps from the primary (first selected) mesh to all other active (selected) meshes (map is created if required). | |
# Transfer happens via vertex index, if the two meshes have different vertex counts nothing will happen. | |
# If no weight maps are selected, all are transferred. | |
# Optional target map argument will cause the first selected weight map found on the primary mesh to be transferred to a weight map of the given name on the active mesh (map is created on the active mesh if required). | |
# NOTE: With the optional map argument given, only one map will be transferred. | |
import lx | |
import lxifc | |
import lxu.command | |
#_______________________________________________________________________________________________________________________ VISITORS | |
class ListMaps (lxifc.Visitor): | |
def __init__ (self, meshmap_from, meshmap_to): | |
self.meshmap_from = meshmap_from | |
self.meshmap_to = meshmap_to | |
self.meshmap_IDs_from = [] | |
self.meshmap_IDs_to = [] | |
def vis_Evaluate (self): | |
meshmap_name = self.meshmap_from.Name () | |
try: | |
self.meshmap_to.SelectByName (lx.symbol.i_VMAP_WEIGHT, meshmap_name) | |
meshmap_to_ID = self.meshmap_to.ID () | |
except: | |
meshmap_to_ID = self.meshmap_to.New (lx.symbol.i_VMAP_WEIGHT, meshmap_name) | |
self.meshmap_IDs_from.append (self.meshmap_from.ID ()) | |
self.meshmap_IDs_to.append (meshmap_to_ID) | |
class TransferWeightByIndex_Cmd(lxu.command.BasicCommand): | |
#______________________________________________________________________________________________ SETUP AND INITIALISATION | |
def __init__(self): | |
lxu.command.BasicCommand.__init__(self) | |
self.dyna_Add ('target', lx.symbol.sTYPE_STRING) | |
self.basic_SetFlags (0, lx.symbol.fCMDARG_OPTIONAL) | |
def cmd_UserName(self): | |
return 'Transfer Weights by Index' | |
def cmd_Desc(self): | |
return 'Transfer all selected weight maps values from primary mesh to all other selected meshes based on vertex index.' | |
def cmd_Tooltip(self): | |
return 'Transfer all selected weight maps values from primary mesh to all other selected meshes based on vertex index.' | |
def cmd_Help(self): | |
return 'http://www.farfarer.com/' | |
def basic_ButtonName(self): | |
return 'Transfer Weights by Index' | |
def cmd_Flags(self): | |
return lx.symbol.fCMD_MODEL | lx.symbol.fCMD_UNDO | lx.symbol.fCMD_SELECT | |
def basic_Enable(self, msg): | |
return True | |
def cmd_Interact(self): | |
pass | |
#_______________________________________________________________________________________________ MAIN FUNCTION EXECUTION | |
def basic_Execute(self, msg, flags): | |
target_map = None | |
if self.dyna_IsSet (0): | |
target_map = self.dyna_String (0) | |
if len (target_map) == 0: | |
target_map = None | |
have_target_map = (target_map is not None) | |
# try: | |
# Grab the active and background layers. | |
layer_svc = lx.service.Layer () | |
sel_svc = lx.service.Selection () | |
# Get the two layers. | |
layer_scan = lx.object.LayerScan (layer_svc.ScanAllocate (lx.symbol.f_LAYERSCAN_EDIT)) | |
if not layer_scan.test (): | |
return | |
layer_scan_count = layer_scan.Count () | |
if layer_scan_count < 2: | |
return | |
sel_weightmaps = [] | |
sel_type_vmap = sel_svc.LookupType (lx.symbol.sSELTYP_VERTEXMAP) | |
vmap_pkt_trans = lx.object.VMapPacketTranslation (sel_svc.Allocate (lx.symbol.sSELTYP_VERTEXMAP)) | |
sel_vmap_count = sel_svc.Count (sel_type_vmap) | |
if sel_vmap_count > 0: | |
for vmap_idx in xrange (sel_vmap_count): | |
pkt = sel_svc.ByIndex (sel_type_vmap, vmap_idx) | |
vmap_type = vmap_pkt_trans.Type (pkt) | |
if vmap_type == lx.symbol.i_VMAP_WEIGHT: | |
sel_weightmaps.append (vmap_pkt_trans.Name (pkt)) | |
maps_selected = (len (sel_weightmaps) > 0) | |
# Work out which is the primary active layer (destination) and which is the background layer (source). | |
primary_layer_index = -1 | |
for layer in xrange (layer_scan_count): | |
if layer_scan.GetState (layer) == (lx.symbol.f_LAYERSCAN_PRIMARY | lx.symbol.f_LAYERSCAN_ACTIVE): | |
primary_layer_index = layer | |
# Early out if a primary layer has not been found. | |
if primary_layer_index == -1: | |
return | |
# Grab the mesh and accessors. | |
mesh_from = lx.object.Mesh (layer_scan.MeshBase (primary_layer_index)) | |
point_from = lx.object.Point (mesh_from.PointAccessor ()) | |
meshmap_from = lx.object.MeshMap (mesh_from.MeshMapAccessor ()) | |
if not mesh_from.test () or not point_from.test () or not meshmap_from.test (): | |
return | |
point_count_from = mesh_from.PointCount () | |
if point_count_from == 0: | |
return | |
for layer in xrange (layer_scan_count): | |
if layer == primary_layer_index: | |
continue | |
# Grab the mesh. | |
mesh_to = lx.object.Mesh (layer_scan.MeshEdit (layer)) | |
if not mesh_to.test (): | |
continue | |
# Early out if either of the layers are empty. | |
point_count_to = mesh_to.PointCount () | |
if point_count_to == 0: | |
continue | |
# Early out if the point count differs. | |
if point_count_to != point_count_from: | |
continue | |
# Grab the accessors needed. | |
point_to = lx.object.Point (mesh_to.PointAccessor ()) | |
if not point_to.test (): | |
continue | |
meshmap_to = lx.object.MeshMap (mesh_to.MeshMapAccessor ()) | |
if not meshmap_to.test (): | |
continue | |
# Get a list of the weight maps shared by the foreground and the background meshes. | |
meshmap_IDs_to = [] | |
meshmap_IDs_from = [] | |
if maps_selected: | |
# Do first selected map to specific map. | |
for sel_weightmap in sel_weightmaps: | |
try: | |
meshmap_from.SelectByName (lx.symbol.i_VMAP_WEIGHT, sel_weightmap) | |
except: | |
pass # Background mesh doesn't have this weight map keep trying until we find one. | |
else: | |
mapname = target_map if have_target_map else sel_weightmap | |
try: | |
meshmap_to.SelectByName (lx.symbol.i_VMAP_WEIGHT, mapname) | |
meshmap_ID_to = meshmap_to.ID () | |
except: | |
meshmap_ID_to = meshmap_to.New (lx.symbol.i_VMAP_WEIGHT, mapname) | |
meshmap_IDs_to.append (meshmap_ID_to) | |
meshmap_IDs_from.append (meshmap_from.ID ()) | |
if have_target_map: | |
break | |
elif not have_target_map: | |
# Do all maps. | |
visitor = ListMaps (meshmap_from, meshmap_to) | |
meshmap_from.FilterByType (lx.symbol.i_VMAP_WEIGHT) | |
meshmap_from.Enumerate (lx.symbol.iMARK_ANY, visitor, 0) | |
meshmap_IDs_from = visitor.meshmap_IDs_from | |
meshmap_IDs_to = visitor.meshmap_IDs_to | |
meshmap_from.FilterByType (0) | |
# Go through each point and copy the values of each weight map from the background mesh to the foreground mesh. | |
for p in xrange (point_count_from): | |
point_from.SelectByIndex (p) | |
point_to.SelectByIndex (p) | |
for from_ID, to_ID in zip(meshmap_IDs_from, meshmap_IDs_to): | |
weight = lx.object.storage ('f', 1) | |
try: | |
res = point_from.MapEvaluate (from_ID, weight) | |
except: | |
point_to.ClearMapValue (to_ID) | |
else: | |
if res: | |
point_to.SetMapValue (to_ID, weight) | |
else: | |
point_to.ClearMapValue (to_ID) | |
# Apply changes. | |
layer_scan.SetMeshChange (layer, lx.symbol.f_MESHEDIT_MAP_OTHER) | |
layer_scan.Apply () | |
#________________________________________________________________________________________ BLESS FUNCTION AS MODO COMMAND | |
lx.bless (TransferWeightByIndex_Cmd, 'ffr.transferWeightByIndex') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment