def _reference_alembic(self, alembic_file, namespace, parent): """ Internal function that references given alembic file :param alembic_file: str :param namespace: str :return: """ all_nodes = alembic.reference_alembic(project=self._project, alembic_file=alembic_file, namespace=namespace) if not all_nodes: logger.warning( 'Error while reference Alembic file: {}'.format(alembic_file)) return for obj in all_nodes: if not dcc.node_exists(obj): continue if not dcc.client().node_type(obj) == 'transform': continue obj_parent = dcc.client().node_parent(obj) if obj_parent: continue dcc.client().set_parent(node=obj, parent=parent) return all_nodes
def _import_mesh_obj(self, data_path): """ Internal function that imports mesh object stored in given path :param data_path: str, path that contains already exported mesh object :return: str, name of the imported mesh """ dependencies = self.get_dependencies(data_path) mesh_path = dependencies.get('geo_file', None) if not mesh_path or not os.path.isfile(mesh_path): mesh_path = path_utils.join_path(data_path, 'mesh.obj') if not path_utils.is_file(mesh_path): return None nodes = dcc.client().list_nodes(node_type='mesh', full_path=False) dcc.client().import_file(mesh_path, import_type='OBJ', ignore_version=True, options='mo=1') current_nodes = dcc.client().list_nodes(node_type='mesh', full_path=False) delta = list(set(current_nodes).difference(nodes)) if delta: delta = dcc.client().node_parent(delta, full_path=True) return delta
def parse_object(self, name): """ Returns the object data for the given object name :param name: str :return: dict """ attrs = list( set(dcc.client().list_attributes(name, unlocked=True, keyable=True) or list())) attrs = [utils.Attribute(name, attr) for attr in attrs] data_dict = { 'attrs': self.attrs(name), 'uuid': dcc.client().node_handle(name) } for attr in attrs: if not attr.is_valid(): continue if attr.value is None: logger.warning( 'Cannot save the attribute {} with value None'.format( attr.fullname)) else: data_dict['attrs'][attr.attr] = { 'type': attr.type, 'value': attr.value } return data_dict
def _on_import_alembic(self, as_reference=False): """ Internal callback function that is called when Import/Reference Alembic button is clicked :param as_reference: bool """ abc_file = self._alembic_path_line.text() if not abc_file or not os.path.isfile(abc_file): dcc.client().confirm_dialog( title='Error', message= 'No Alembic File is selected or file is not currently available in disk' ) return None abc_name = os.path.basename(abc_file).split('.')[0] tag_json_file = os.path.join( os.path.dirname(abc_file), os.path.basename(abc_file).replace('.abc', '_abc.info')) valid_tag_info = True if os.path.isfile(tag_json_file): with open(tag_json_file, 'r') as f: tag_info = json.loads(f.read()) if not tag_info: logger.warning('No Alembic Info loaded!') valid_tag_info = False else: logger.warning('No Alembic Info file found!') valid_tag_info = False if as_reference: reference_nodes = self._reference_alembic(alembic_file=abc_file, namespace=abc_name) else: reference_nodes = self._import_alembic( alembic_file=abc_file, valid_tag_info=valid_tag_info) reference_nodes = python.force_list(reference_nodes) added_tag = False for key in tag_info.keys(): if reference_nodes: for obj in reference_nodes: short_obj = dcc.client().node_short_name(obj) if key == short_obj: self._add_tag_info_data(self._project, tag_info[key], obj) added_tag = True if not added_tag: self._add_tag_info_data(self._project, tag_info, reference_nodes[0]) if reference_nodes: if as_reference: self.showOk.emit('Alembic file referenced successfully!') else: self.showOk.emit('Alembic file imported successfully!') return reference_nodes
def ls(cls, objects=None, selection=False): if objects is None and not selection: objects = dcc.client().all_scene_nodes(full_path=False) else: objects = objects or list() if selection: objects.extend(dcc.client().selected_nodes(full_path=False) or []) return [cls(name) for name in objects]
def __call__(self, *args, **kwargs): if dcc.client().is_maya(): from artellapipe.tools.alembicmanager.dccs.maya import importer return type.__call__(importer.MayaAlembicImporter, *args, **kwargs) elif dcc.client().is_houdini(): from artellapipe.tools.alembicmanager.dccs.houdini import importer return type.__call__(importer.HoudiniAlembicImporter, *args, **kwargs) else: return type.__call__(BaseAlembicImporter, *args, **kwargs)
def load(self): """ Opens OS explorer where data is located """ filepath = self.format_identifier() if not filepath.endswith(MayaBinaryData.EXTENSION): filepath = '{}{}'.format(filepath, MayaBinaryData.EXTENSION) if not filepath or not os.path.isfile(filepath): return dcc.client().open_file(filepath)
def _recursive_hierarchy(transform): child_nodes = list() if not transform: return child_nodes transforms = dcc.client().list_relatives(node=transform, full_path=True) if not transforms: return child_nodes for eachTransform in transforms: if dcc.client().node_type(eachTransform) == 'transform': child_nodes.append(eachTransform) child_nodes.extend(_recursive_hierarchy(eachTransform)) return child_nodes
def save(self, *args, **kwargs): filepath = self.format_identifier() if not filepath.endswith(ControlCVsData.EXTENSION): filepath = '{}{}'.format(filepath, ControlCVsData.EXTENSION) if not filepath: logger.warning( 'Impossible to save Control CVs file because save file path not defined!' ) return logger.debug('Saving {} | {}'.format(filepath, kwargs)) objects = kwargs.get('objects', None) if not objects: objects = dcc.client().selected_nodes(full_path=True) if not objects: logger.warning( 'Nothing selected to export Control CVs of. Please, select a curve to export' ) return False # We make sure that we store the short name of the controls objects = [dcc.client().node_short_name(obj) for obj in objects] controls = objects or controllib.get_controls() valid_controls = list() for control in controls: if not controllib.is_control(control): continue valid_controls.append(control) if not valid_controls: logger.warning('No valid controls found to export.') return False library = self._initialize_library(filepath) if not controls: logger.warning('No controls found to export.') return False for control in controls: library.add_curve(control) library.write_data_to_file() logger.info('Saved {} data'.format(self.name())) return True
def get_reference_paths(objects, without_copy_number=False): """ Returns the reference paths for the given objects :param objects: list(str) :param without_copy_number: bool :return: list(str) """ paths = list() for obj in objects: if dcc.client().node_is_referenced(obj): paths.append(dcc.client().node_reference_path( obj, without_copy_number=without_copy_number)) return list(set(paths))
def export_data(self, *args, **kwargs): filepath = self.format_identifier() if not filepath.endswith(TransformsData.EXTENSION): filepath = '{}{}'.format(filepath, TransformsData.EXTENSION) if not filepath or not os.path.isfile(filepath): LOGGER.warning( 'Impossible to export transforms data to: "{}"'.format( filepath)) return LOGGER.debug('Exporting: {} | {}'.format(filepath, kwargs)) with open(filepath, 'r') as fh: transforms_data = json.load(fh) if not transforms_data: LOGGER.warning( 'No transforms data found in file: "{}"'.format(filepath)) return False selected_nodes = dcc.client().selected_nodes(full_path=False) saved_nodes = list() if not selected_nodes: for node_data in transforms_data: node_name = node_data.get('name') if not node_name: continue saved_nodes.append(node_name) else: for selected_node in selected_nodes: if selected_node not in saved_nodes: saved_nodes.append(selected_node) valid_nodes = list() for selected_node in saved_nodes: if not dcc.client().node_exists(selected_node) or not dcc.client( ).node_is_transform(selected_node): continue valid_nodes.append(selected_node) if not valid_nodes: LOGGER.warning( 'No transforms to export to file found: "{}"'.format(filepath)) return False return self.save(objects=valid_nodes)
def save(self, *args, **kwargs): from tpDcc.libs.datalibrary.dccs.maya.core import pose filepath = self.format_identifier() if not filepath.endswith(PoseData.EXTENSION): filepath = '{}{}'.format(filepath, PoseData.EXTENSION) if not filepath: logger.warning('Impossible to save pose file because save file path not defined!') return objects = kwargs.get('objects', None) if not objects: objects = dcc.client().selected_nodes(full_path=True) if not objects: logger.warning('Select objects to export pose from') return False logger.debug('Saving {} | {}'.format(filepath, kwargs)) new_pose = pose.Pose.from_objects(objects=objects) try: new_pose.save(filepath) except IOError: logger.error('Pose data not saved to file {}'.format(filepath)) return False logger.debug('Saved {} successfully!'.format(filepath)) return True
def is_locked(self): """ Returns True if the attribute is locked; False otherwise. :return: bool """ return dcc.client().is_attribute_locked(self.name, self.attr)
def load_validator(self, **options): namespaces = options.get('namespaces') namespace_option = options.get('namespaceOption') if namespace_option == 'From file': namespaces = list() # namespaces = self.metadata().get('namespaces', list()) elif namespace_option == 'From selection': namespaces = dcc.client().list_namespaces_from_selection() or [''] field_changed = options.get('fieldChanged') if field_changed == 'namespaces': options['namespaceOption'] = 'Use custom' else: options['namespaceOption'] = namespaces self._current_load_values = options return [{ "name": "namespaces", "value": options.get("namespaces") }, { "name": "namespaceOption", "value": options.get("namespaceOption") }]
def is_valid(self): """ Returns True if the attribute type is valid; False otherwise. :return: bool """ return self.type in dcc.client().get_valid_attribute_types()
def _add_tag_info_data(project, tag_info, attr_node): """ Internal function that updates the tag info of the Alembic node :param project: ArtellaProject :param tag_info: dict :param attr_node: str """ if not dcc.client().attribute_exists(node=attr_node, attribute_name='tag_info'): dcc.client().add_string_attribute(node=attr_node, attribute_name='tag_info', keyable=True) dcc.client().set_string_attribute_value(node=attr_node, attribute_name='tag_info', attribute_value=str(tag_info))
def import_data(self, *args, **kwargs): filepath = self.format_identifier() if not filepath.endswith(MayaCurveData.EXTENSION): filepath = '{}{}'.format(filepath, MayaCurveData.EXTENSION) if not filepath: LOGGER.warning( 'Impossible to load Maya Curves from file: "{}"!'.format( filepath)) return False with open(filepath, 'r') as fh: curves_data = json.load(fh) if not curves_data: LOGGER.warning( 'No curves data found in file: "{}"'.format(filepath)) return False created_curves = list() for curve_name, curve_data in curves_data.items(): new_curve = dcc.client().create_curve(curve_name, **curve_data) created_curves.append(new_curve) return created_curves
def load_schema(self): return [{ 'name': 'namespaceGroup', 'title': 'Namespace', 'type': 'group', 'order': 10, }, { 'name': 'namespaceOption', 'title': '', 'type': 'radio', 'value': 'From file', 'items': ['From file', 'From selection', 'Use custom'], 'persistent': True, 'persistentKey': 'MayaAsciiData', }, { 'name': 'namespaces', 'title': '', 'type': 'tags', 'value': [], 'items': dcc.client().list_namespaces(), 'persistent': True, 'label': { 'visible': False }, 'persistentKey': 'MayaAsciiData' }]
def _refresh_frame_ranges(self): """ Internal function that updates the frame ranges values """ frame_range = dcc.client().get_time_slider_range() self._start.setValue(int(frame_range[0])) self._end.setValue(int(frame_range[1]))
def _create_alembic_group(cls, group_name): """ Internal function that creates root gruop for Alembic Node :return: str """ root = dcc.client().create_empty_group(name=group_name) return root
def type(self): """ Returns the type of data currently in the attribute :return: str """ if self._type is None: try: if dcc.client().attribute_exists(self.name, self.attr): self._type = dcc.client().get_attribute_type( self.name, self.attr) if self._type: self._type = self._type.encode('ascii') except Exception: logger.exception('Cannot get attribute type for "{}'.format( self.fullname)) return self._type
def _get_tag_atributes_dict(self, tag_node): # We add attributes to the first node in the list tag_info = dict() if not tag_node: return tag_info attrs = dcc.client().list_user_attributes(tag_node) for attr in attrs: try: tag_info[attr] = dcc.client().get_attribute_value( node=tag_node, attribute_name=attr) except Exception: pass if not tag_info: logger.warning('Node has not valid tag data: {}'.format(tag_node)) return return tag_info
def create(cls, tool_id, *args, **kwargs): # If a client with given ID is already registered, we return it client = dcc.client(tool_id, only_clients=True) if client: return client client = cls(tool_id=tool_id) return client
def _on_browse_alembic(self): """ Internal callback function that is called when Browse Alembic File button is clicked """ shot_name = self._shot_line.text() abc_folder = os.path.normpath( os.path.join(self._project.get_path(), shot_name) ) if shot_name != 'unresolved' else self._project.get_path() pattern = 'Alembic Files (*.abc)' if dcc.client().is_houdini(): pattern = '*.abc' abc_file = dcc.client().select_file_dialog( title='Select Alembic to Import', start_directory=abc_folder, pattern=pattern) if abc_file: self._alembic_path_line.setText(abc_file)
def value(self): if self._value is None or not self._cache: try: self._value = dcc.client().get_attribute_value( self.name, self.attr) except Exception: logger.exception('Cannot get attribute value for "{}'.format( self.fullname)) return self._value
def to_short_name(self): names = dcc.client().list_nodes(node_name=self.short_name(), full_path=False) or list() if len(names) == 1: return Node(names[0]) elif len(names) > 1: raise exceptions.MoreThanOneObjectFoundError( 'More than one object found {}'.format(str(names))) else: raise exceptions.NoObjectFoundError('No object found {}'.format( self.short_name()))
def load(cls): # Initialize environment variable that contains paths were curves libs command are located # This environment variable is used by the command runner dcc_name = dcc.client().get_name() commands_path = path_utils.clean_path( os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'dccs', dcc_name, 'commands')) if os.path.isdir(commands_path): command.CommandRunner().manager().register_path( commands_path, 'tpDcc')
def import_data(self, **kwargs): filepath = self.format_identifier() if not filepath.endswith(ControlCVsData.EXTENSION): filepath = '{}{}'.format(filepath, ControlCVsData.EXTENSION) if not filepath: logger.warning( 'Impossible to load Control CVs from file: "{}"!'.format( filepath)) return False library = self._initialize_library(filepath) objects = kwargs.get('objects', None) if not objects: objects = dcc.client().selected_nodes(full_path=True) or list() # We make sure that we store the short name of the controls objects = [dcc.node_short_name(obj) for obj in objects] updated_controls = list() controls = objects or controllib.get_controls() for control in controls: shapes = dcc.client().get_curve_shapes(control) if not shapes: continue library.set_curve(control, check_curve=True) updated_controls.append(control) # We force the update of all the curves that are stored in the library and are in the scene for curve_data in list(library._library_curves.values()): for curve_name in list(curve_data.keys()): if curve_name and dcc.node_exists( curve_name) and curve_name not in updated_controls: library.set_curve(curve_name, check_curve=True) updated_controls.append(curve_name) logger.info('Imported {} data'.format(self.name())) return True
def _refresh_alembic_name(self): """ Internal function that updates Alembic name """ if self._name_line.text() != '': return sel = dcc.client().selected_nodes() if sel: sel = sel[0] is_referenced = dcc.client().node_is_referenced(sel) if is_referenced: sel_namespace = dcc.client().node_namespace(sel) if not sel_namespace or not sel_namespace.startswith(':'): pass else: sel_namespace = sel_namespace[1:] + ':' sel = sel.replace(sel_namespace, '') self._name_line.setText(dcc.client().node_short_name(sel))
def run(self, influence_index, skin, weights, file_path): influence_name = dcc.client().get_skin_influence_at_index( influence_index, skin) if not influence_name or not dcc.client().node_exists(influence_name): return None, None weight_path = fileio.create_file('{}.weights'.format(influence_name), file_path) if not path_utils.is_file(weight_path): logger.warning( '"{}" is not a valid path to save skin weights into!'.format( file_path)) return None, None writer = fileio.FileWriter(weight_path) writer.write_line(weights) influence_position = dcc.client().node_world_space_translation( influence_name) return "{'%s' : {'position' : %s}}" % ( influence_name, str(influence_position)), weight_path