class StreamlinesPanel(bpy.types.Panel): """ Panel containing operators to position neuron morphology around DBS electrode. """ # Panel parameters bl_space_type = 'VIEW_3D' bl_region_type = 'TOOLS' bl_label = 'Track Positioning' bl_category = 'NeuroMorphoVis' bl_options = {'DEFAULT_CLOSED'} # -------------------------------------------------------------------------- # Properties for UI state # Streamlines file debug_tck_file = '/home/luye/Documents/mri_data/Waxholm_rat_brain_atlas/WHS_DTI_v1_ALS/S56280_track_filter-ROI-STN.tck' default_tck_file = debug_tck_file if DEBUG else 'Select File' bpy.types.Scene.StreamlinesFile = StringProperty( name="Streamlines File", description="Select streamlines file", default=default_tck_file, maxlen=2048, subtype='FILE_PATH') bpy.types.Scene.StreamlinesLabel = StringProperty( name="Label", description= "Enter label for streamlines in file (supported by pickle files)", default='') # ISSUE when loading numpy data saved using Python 2.x -> encoding must be 'latin1' bpy.types.Scene.StreamlinesEncoding = StringProperty( name="Encoding", description="Encoding of streamlines if using Python pickle file.", default='latin1') bpy.types.Scene.MaxLoadStreamlines = IntProperty( name="Max Streamlines", description="Maximum number of loaded streamlines", default=100, min=1, max=10000) bpy.types.Scene.MinStreamlineLength = FloatProperty( name="Min Length", description="Minimum streamline length (mm)", default=1.0, min=1.0, max=1e6) bpy.types.Scene.StreamlineUnitScale = FloatProperty( name="Scale", description="Streamline scale relative to microns (units/um)", default=1e3, min=1e-12, max=1e12) bpy.types.Scene.RoiName = StringProperty( name="ROI Name", description="Name for selected ROI volume", default='ROI-1') bpy.types.Scene.SampleSpacing = FloatProperty( name="Spacing", description="Spacing between streamline samples.", default=100.0) bpy.types.Scene.SubsampleFactor = IntProperty( name="Subsample factor", description="Subsample factor", default=1) # -------------------------------------------------------------------------- # Panel overriden methods def draw(self, context): """ Layout UI elements in the panel. :param context: Rendering context """ layout = self.layout scene = context.scene # File Paths ----------------------------------------------------------- layout.row().label(text='Import streamlines:', icon='LIBRARY_DATA_DIRECT') # Select directory layout.row().prop(scene, 'StreamlinesFile') layout.row().prop(scene, 'StreamlinesLabel') layout.row().prop(scene, 'StreamlinesEncoding') # Import Options ------------------------------------------------------- # labels for PRE and POST synaptic populations # row_pops_header = layout.row() # row_pops_header.column(align=True).label(text='Pre-syn.') # row_pops_header.column(align=True).label(text='Post-syn.') # row_pops_fields = layout.row() # row_pops_fields.column(align=True).prop( # context.scene, 'ProjectionPrePopLabel', text='') # row_pops_fields.column(align=True).prop( # context.scene, 'ProjectionPostPopLabel', text='') layout.row().prop(context.scene, 'MaxLoadStreamlines') layout.row().prop(context.scene, 'MinStreamlineLength') layout.row().prop(context.scene, 'StreamlineUnitScale') # Draw Streamlines layout.column(align=True).operator('import.streamlines', icon='IMPORT') # Edit ----------------------------------------------------------------- layout.row().label(text='Edit streamlines:', icon='IPO') layout.column(align=True).operator(AttachAxonToNeuron.bl_idname, icon='SNAP_SURFACE') layout.row().prop(context.scene, 'SampleSpacing') layout.column(align=True).operator(SplineToPolyline.bl_idname, icon='ALIGN', text='Sample streamline') layout.row().prop(context.scene, 'SubsampleFactor') layout.column(align=True).operator(PolylineToSpline.bl_idname, icon='PARTICLE_POINT', text='Streamline to NURBS') # ROIs ----------------------------------------------------------------- layout.row().label(text='ROIs:', icon='ALIASED') # ROI name layout.row().prop(context.scene, 'RoiName') layout.column(align=True).operator('add.roi', icon='IMPORT') layout.column(align=True).operator(ScaleROI.bl_idname, icon='MAN_SCALE') layout.column(align=True).operator('view3d.view_selected', icon='RESTRICT_VIEW_OFF') # Exporting ------------------------------------------------------------ layout.row().label(text='Export Streamlines:', icon='LIBRARY_DATA_DIRECT') layout.column(align=True).operator('axon.toggle_export', icon='EXPORT') layout.column(align=True).operator('export.streamlines', icon='SAVE_COPY')
class PREFERENCES_OT_keyconfig_import(Operator): """Import key configuration from a python script""" bl_idname = "preferences.keyconfig_import" bl_label = "Import Key Configuration..." filepath: StringProperty( subtype='FILE_PATH', default="keymap.py", ) filter_folder: BoolProperty( name="Filter folders", default=True, options={'HIDDEN'}, ) filter_text: BoolProperty( name="Filter text", default=True, options={'HIDDEN'}, ) filter_python: BoolProperty( name="Filter python", default=True, options={'HIDDEN'}, ) keep_original: BoolProperty( name="Keep original", description="Keep original file after copying to configuration folder", default=True, ) def execute(self, _context): import os from os.path import basename import shutil if not self.filepath: self.report({'ERROR'}, "Filepath not set") return {'CANCELLED'} config_name = basename(self.filepath) path = bpy.utils.user_resource('SCRIPTS', os.path.join("presets", "keyconfig"), create=True) path = os.path.join(path, config_name) try: if self.keep_original: shutil.copy(self.filepath, path) else: shutil.move(self.filepath, path) except Exception as ex: self.report({'ERROR'}, "Installing keymap failed: %s" % ex) return {'CANCELLED'} # sneaky way to check we're actually running the code. if bpy.utils.keyconfig_set(path, report=self.report): return {'FINISHED'} else: return {'CANCELLED'} def invoke(self, context, _event): wm = context.window_manager wm.fileselect_add(self) return {'RUNNING_MODAL'}
class PREFERENCES_OT_app_template_install(Operator): """Install an application-template""" bl_idname = "preferences.app_template_install" bl_label = "Install Template from File..." overwrite: BoolProperty( name="Overwrite", description="Remove existing template with the same ID", default=True, ) filepath: StringProperty( subtype='FILE_PATH', ) filter_folder: BoolProperty( name="Filter folders", default=True, options={'HIDDEN'}, ) filter_glob: StringProperty( default="*.zip", options={'HIDDEN'}, ) def execute(self, _context): import traceback import zipfile import os filepath = self.filepath path_app_templates = bpy.utils.user_resource( 'SCRIPTS', os.path.join("startup", "bl_app_templates_user"), create=True, ) if not path_app_templates: self.report({'ERROR'}, "Failed to get add-ons path") return {'CANCELLED'} if not os.path.isdir(path_app_templates): try: os.makedirs(path_app_templates, exist_ok=True) except: traceback.print_exc() app_templates_old = set(os.listdir(path_app_templates)) # check to see if the file is in compressed format (.zip) if zipfile.is_zipfile(filepath): try: file_to_extract = zipfile.ZipFile(filepath, 'r') except: traceback.print_exc() return {'CANCELLED'} if self.overwrite: for f in file_to_extract.namelist(): module_filesystem_remove(path_app_templates, f) else: for f in file_to_extract.namelist(): path_dest = os.path.join(path_app_templates, os.path.basename(f)) if os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} try: # extract the file to "bl_app_templates_user" file_to_extract.extractall(path_app_templates) except: traceback.print_exc() return {'CANCELLED'} else: # Only support installing zipfiles self.report({'WARNING'}, "Expected a zip-file %r\n" % filepath) return {'CANCELLED'} app_templates_new = set(os.listdir(path_app_templates)) - app_templates_old # in case a new module path was created to install this addon. bpy.utils.refresh_script_paths() # print message msg = ( tip_("Template Installed (%s) from %r into %r") % (", ".join(sorted(app_templates_new)), filepath, path_app_templates) ) print(msg) self.report({'INFO'}, msg) return {'FINISHED'} def invoke(self, context, _event): wm = context.window_manager wm.fileselect_add(self) return {'RUNNING_MODAL'}
class SvPresetProps(bpy.types.Operator): """ Edit preset properties """ bl_idname = "node.sv_preset_props" bl_label = "Preset properties" bl_options = {'INTERNAL'} old_name: StringProperty(name="Old name", description="Preset name") new_name: StringProperty(name="Name", description="New preset name") description: StringProperty(name="Description", description="Preset description") author: StringProperty(name="Author", description="Preset author name") license: StringProperty(name="License", description="Preset license (short name)", default="CC-BY-SA") def draw(self, context): layout = self.layout layout.prop(self, "new_name") layout.prop(self, "description") layout.prop(self, "author") layout.prop(self, "license") def execute(self, context): if not self.old_name: msg = "Old preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if not self.new_name: msg = "New preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} preset = SvPreset(name=self.old_name) preset.meta['description'] = self.description preset.meta['author'] = self.author preset.meta['license'] = self.license preset.save() if self.new_name != self.old_name: old_path = get_preset_path(self.old_name) new_path = get_preset_path(self.new_name) if os.path.exists(new_path): msg = "Preset named `{}' already exists. Refusing to rewrite existing preset.".format( self.new_name) error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} os.rename(old_path, new_path) preset.name = self.new_name info("Renamed `%s' to `%s'", old_path, new_path) self.report({'INFO'}, "Renamed `{}' to `{}'".format(self.old_name, self.new_name)) bpy.utils.unregister_class(preset_add_operators[self.old_name]) del preset_add_operators[self.old_name] preset.make_add_operator() return {'FINISHED'} def invoke(self, context, event): wm = context.window_manager self.new_name = self.old_name preset = SvPreset(name=self.old_name) self.description = preset.meta.get('description', "") self.author = preset.meta.get('author', "") self.license = preset.meta.get('license', "CC-BY-SA") return wm.invoke_props_dialog(self)
class ImportOWMDL(bpy.types.Operator, ImportHelper): bl_idname = 'import_mesh.overtools_model' bl_label = 'Import Overtools Model (owmdl)' bl_options = {'UNDO'} filename_ext = '.owmdl' filter_glob: StringProperty( default='*.owmdl', options={'HIDDEN'}, ) uvDisplX: IntProperty( name='X', description='Displace UV X axis', default=0, ) uvDisplY: IntProperty( name='Y', description='Displace UV Y axis', default=0, ) autoIk: BoolProperty( name='AutoIK', description='Set AutoIK', default=True, ) importNormals: BoolProperty( name='Import Normals', description='Import Custom Normals', default=True, ) importColor: BoolProperty( name='Import Color', description='Import Custom Colors', default=True, ) importEmpties: BoolProperty( name='Import Hardpoints', description='Import Hardpoints (attachment points)', default=False, ) importMaterial: BoolProperty( name='Import Material', description='Import Referenced OWMAT', default=True, ) importSkeleton: BoolProperty( name='Import Skeleton', description='Import Bones', default=True, ) def menu_func(self, context): self.layout.operator_context = 'INVOKE_DEFAULT' self.layout.operator(ImportOWMDL.bl_idname, text='Text Export Operator') @classmethod def poll(cls, context): return True def execute(self, context): settings = owm_types.OWSettings(self.filepath, self.uvDisplX, self.uvDisplY, self.autoIk, self.importNormals, self.importEmpties, self.importMaterial, self.importSkeleton, self.importColor) owm_types.update_data() t = datetime.now() bpyhelper.LOCK_UPDATE = False try: import_owmdl.read(settings) except KeyboardInterrupt: bpyhelper.LOCK_UPDATE = False print('Done. SMPTE: %s' % (smpte_from_seconds(datetime.now() - t))) return {'FINISHED'} def draw(self, context): layout = self.layout col = layout.column(align=True) col.label(text='Mesh') col.prop(self, 'importNormals') col.prop(self, 'importEmpties') col.prop(self, 'importColor') col.prop(self, 'importMaterial') sub = col.row() sub.label(text='UV') sub.prop(self, 'uvDisplX') sub.prop(self, 'uvDisplY') col = layout.column(align=True) col.label(text='Armature') col.prop(self, 'importSkeleton') sub = col.row() sub.prop(self, 'autoIk') sub.enabled = self.importSkeleton
class ImportGLTF2(Operator, ImportHelper): """Load a glTF 2.0 file""" bl_idname = 'import_scene.gltf' bl_label = 'Import glTF 2.0' filter_glob: StringProperty(default="*.glb;*.gltf", options={'HIDDEN'}) files: CollectionProperty( name="File Path", type=bpy.types.OperatorFileListElement, ) loglevel: IntProperty(name='Log Level', description="Log Level") import_pack_images: BoolProperty( name='Pack images', description='Pack all images into .blend file', default=True) import_shading: EnumProperty( name="Shading", items=(("NORMALS", "Use Normal Data", ""), ("FLAT", "Flat Shading", ""), ("SMOOTH", "Smooth Shading", "")), description="How normals are computed during import", default="NORMALS") def draw(self, context): layout = self.layout layout.prop(self, 'import_pack_images') layout.prop(self, 'import_shading') def execute(self, context): return self.import_gltf2(context) def import_gltf2(self, context): import os self.set_debug_log() import_settings = self.as_keywords() if self.files: # Multiple file import ret = {'CANCELLED'} dirname = os.path.dirname(self.filepath) for file in self.files: path = os.path.join(dirname, file.name) if self.unit_import(path, import_settings) == {'FINISHED'}: ret = {'FINISHED'} return ret else: # Single file import return self.unit_import(self.filepath, import_settings) def unit_import(self, filename, import_settings): import time from .io.imp.gltf2_io_gltf import glTFImporter from .blender.imp.gltf2_blender_gltf import BlenderGlTF self.gltf_importer = glTFImporter(filename, import_settings) success, txt = self.gltf_importer.read() if not success: self.report({'ERROR'}, txt) return {'CANCELLED'} success, txt = self.gltf_importer.checks() if not success: self.report({'ERROR'}, txt) return {'CANCELLED'} self.gltf_importer.log.critical( "Data are loaded, start creating Blender stuff") start_time = time.time() BlenderGlTF.create(self.gltf_importer) elapsed_s = "{:.2f}s".format(time.time() - start_time) self.gltf_importer.log.critical("glTF import finished in " + elapsed_s) self.gltf_importer.log.removeHandler(self.gltf_importer.log_handler) return {'FINISHED'} def set_debug_log(self): import logging if bpy.app.debug_value == 0: self.loglevel = logging.CRITICAL elif bpy.app.debug_value == 1: self.loglevel = logging.ERROR elif bpy.app.debug_value == 2: self.loglevel = logging.WARNING elif bpy.app.debug_value == 3: self.loglevel = logging.INFO else: self.loglevel = logging.NOTSET
class SunPosProperties(PropertyGroup): usage_mode: EnumProperty( name="Usage mode", description="Operate in normal mode or environment texture mode", items=( ('NORMAL', "Normal", ""), ('HDR', "Sun + HDR texture", ""), ), default='NORMAL', update=sun_update) use_daylight_savings: BoolProperty( name="Daylight savings", description="Daylight savings time adds 1 hour to standard time", default=False, update=sun_update) use_refraction: BoolProperty( name="Use refraction", description="Show apparent sun position due to refraction", default=True, update=sun_update) show_north: BoolProperty(name="Show North", description="Draw line pointing north", default=False, update=north_update) north_offset: FloatProperty( name="North Offset", description="Rotate the scene to choose North direction", unit="ROTATION", soft_min=-pi, soft_max=pi, step=10.0, default=0.0, update=sun_update) latitude: FloatProperty(name="Latitude", description="Latitude: (+) Northern (-) Southern", soft_min=-90.0, soft_max=90.0, step=5, precision=3, default=0.0, update=sun_update) longitude: FloatProperty( name="Longitude", description="Longitude: (-) West of Greenwich (+) East of Greenwich", soft_min=-180.0, soft_max=180.0, step=5, precision=3, default=0.0, update=sun_update) co_parser: StringProperty( name="Enter coordinates", description="Enter coordinates from an online map", update=parse_coordinates) month: IntProperty(name="Month", min=1, max=12, default=TODAY.month, update=sun_update) day: IntProperty(name="Day", min=1, max=31, default=TODAY.day, update=sun_update) year: IntProperty(name="Year", min=1, max=4000, default=TODAY.year, update=sun_update) use_day_of_year: BoolProperty( description="Use a single value for day of year", name="Use day of year", default=False, update=sun_update) day_of_year: IntProperty(name="Day of year", min=1, max=366, default=1, update=sun_update) UTC_zone: FloatProperty( name="UTC zone", description="Time zone: Difference from Greenwich, England in hours", precision=1, min=-14.0, max=13, step=50, default=0.0, update=sun_update) time: FloatProperty(name="Time", description="Time of the day", precision=4, soft_min=0.0, soft_max=23.9999, step=1.0, default=12.0, update=sun_update) sun_distance: FloatProperty(name="Distance", description="Distance to sun from origin", unit="LENGTH", min=0.0, soft_max=3000.0, step=10.0, default=50.0, update=sun_update) sun_object: PointerProperty(name="Sun Object", type=bpy.types.Object, description="Sun object to set in the scene", poll=lambda self, obj: obj.type == 'LIGHT', update=sun_update) object_collection: PointerProperty( name="Collection", type=bpy.types.Collection, description="Collection of objects used to visualize sun motion", update=sun_update) object_collection_type: EnumProperty( name="Display type", description="Show object group as sun motion", items=( ('ANALEMMA', "Analemma", ""), ('DIURNAL', "Diurnal", ""), ), default='ANALEMMA', update=sun_update) sky_texture: StringProperty(name="Sky Texture", default="Sky Texture", description="Name of sky texture to be used", update=sun_update) hdr_texture: StringProperty( default="Environment Texture", name="Environment Texture", description="Name of texture to use. World nodes must be enabled " "and color set to Environment Texture", update=sun_update) hdr_azimuth: FloatProperty( name="Rotation", description="Rotation angle of sun and environment texture", unit="ROTATION", step=10.0, default=0.0, precision=3, update=sun_update) hdr_elevation: FloatProperty(name="Elevation", description="Elevation angle of sun", unit="ROTATION", step=10.0, default=0.0, precision=3, update=sun_update) bind_to_sun: BoolProperty( description="If true, Environment texture moves with sun", default=False, update=sun_update) time_spread: FloatProperty( name="Time Spread", description="Time period in which to spread object collection", precision=4, soft_min=1.0, soft_max=24.0, step=1.0, default=23.0, update=sun_update)
class OctaneThinLensCameraGroupPhysicalCameraParameters( OctaneGroupTitleSocket): bl_idname = "OctaneThinLensCameraGroupPhysicalCameraParameters" bl_label = "[OctaneGroupTitle]Physical Camera parameters" octane_group_sockets: StringProperty( name="Group Sockets", default="Sensor width;Focal length;F-stop;")
class OctaneThinLensCameraGroupClipping(OctaneGroupTitleSocket): bl_idname = "OctaneThinLensCameraGroupClipping" bl_label = "[OctaneGroupTitle]Clipping" octane_group_sockets: StringProperty( name="Group Sockets", default="Near clip depth;Far clip depth;")
class SvFormulaNodeMk3(bpy.types.Node, SverchCustomTreeNode): """ Triggers: Formula Tooltip: Calculate by custom formula. """ bl_idname = 'SvFormulaNodeMk3' bl_label = 'Formula' bl_icon = 'OUTLINER_OB_EMPTY' sv_icon = 'SV_FORMULA' @throttled def on_update(self, context): self.adjust_sockets() @throttled def on_update_dims(self, context): if self.dimensions < 4: self.formula4 = "" if self.dimensions < 3: self.formula3 = "" if self.dimensions < 2: self.formula2 = "" self.adjust_sockets() dimensions: IntProperty(name="Dimensions", default=1, min=1, max=4, update=on_update_dims) formula1: StringProperty(default="x+y", update=on_update) formula2: StringProperty(update=on_update) formula3: StringProperty(update=on_update) formula4: StringProperty(update=on_update) separate: BoolProperty(name="Separate", default=False, update=updateNode) wrap: BoolProperty(name="Wrap", default=False, update=updateNode) def formulas(self): return [self.formula1, self.formula2, self.formula3, self.formula4] def formula(self, k): return self.formulas()[k] def draw_buttons(self, context, layout): layout.prop(self, "formula1", text="") if self.dimensions > 1: layout.prop(self, "formula2", text="") if self.dimensions > 2: layout.prop(self, "formula3", text="") if self.dimensions > 3: layout.prop(self, "formula4", text="") row = layout.row() row.prop(self, "separate") row.prop(self, "wrap") def draw_buttons_ext(self, context, layout): layout.prop(self, "dimensions") self.draw_buttons(context, layout) def sv_init(self, context): self.inputs.new('SvStringsSocket', "x") self.outputs.new('SvStringsSocket', "Result") def get_variables(self): variables = set() for formula in self.formulas(): vs = get_variables(formula) variables.update(vs) return list(sorted(list(variables))) def adjust_sockets(self): variables = self.get_variables() #self.debug("adjust_sockets:" + str(variables)) #self.debug("inputs:" + str(self.inputs.keys())) for key in self.inputs.keys(): if key not in variables: self.debug("Input {} not in variables {}, remove it".format( key, str(variables))) self.inputs.remove(self.inputs[key]) for v in variables: if v not in self.inputs: self.debug("Variable {} not in inputs {}, add it".format( v, str(self.inputs.keys()))) self.inputs.new('SvStringsSocket', v) def update(self): ''' update analyzes the state of the node and returns if the criteria to start processing are not met. ''' if not any(len(formula) for formula in self.formulas()): return self.adjust_sockets() def get_input(self): variables = self.get_variables() inputs = {} for var in variables: if var in self.inputs and self.inputs[var].is_linked: inputs[var] = self.inputs[var].sv_get() # n_max = max(len(inputs[var]) for var in inputs) # result = [] # for i in range(n_max): # item = defaultdict(list) # for var in inputs: # value = inputs[var] # if i < len(value): # item[var].append(value[i]) # else: # item[var].append(value[-1]) # result.append(item) return inputs def migrate_from(self, old_node): if old_node.bl_idname == 'Formula2Node': formula = old_node.formula # Older formula node allowed only fixed set of # variables, with names "x", "n[0]" .. "n[100]". # Other names could not be considered valid. k = -1 for socket in old_node.inputs: name = socket.name if k == -1: # First socket name was "x" new_name = name else: # Other names was "n[k]", which is syntactically not # a valid python variable name. # So we replace all occurences of "n[0]" in formula # with "n0", and so on. new_name = "n" + str(k) logging.info("Replacing %s with %s", name, new_name) formula = formula.replace(name, new_name) k += 1 self.formula1 = formula self.wrap = True def process(self): if not self.outputs[0].is_linked: return var_names = self.get_variables() inputs = self.get_input() results = [] if var_names: input_values = [inputs.get(name, [[0]]) for name in var_names] parameters = match_long_repeat(input_values) else: parameters = [[[]]] for objects in zip(*parameters): object_results = [] for values in zip_long_repeat(*objects): variables = dict(zip(var_names, values)) vector = [] for formula in self.formulas(): if formula: value = safe_eval(formula, variables) vector.append(value) if self.separate: object_results.append(vector) else: object_results.extend(vector) results.append(object_results) if self.wrap: results = [results] self.outputs['Result'].sv_set(results)
class LuxCoreErrorLog(bpy.types.PropertyGroup): errors = StringProperty(name="") def set(self, error): self.errors = str(error)
class SplashExportNodeTree(Operator): """Exports Splash whole configuration, project (only geometry and image data), or 3D models""" bl_idname = "splash.export_node_tree" bl_label = "Exports the node tree" filepath = bpy.props.StringProperty(subtype='FILE_PATH') filter_glob = bpy.props.StringProperty( default="*.json", options={'HIDDEN'}, ) node_name = StringProperty(name='Node name', description='Name of the calling node', default='') export_project = BoolProperty( name='export_project', description= 'If True, the tree will contain only meshes and images data', default=False) export_only_nodes = BoolProperty( name='export_only_nodes', description= 'If True, the tree is not exported, but nodes are evaluated anyway', default=False) world_node = None scene_order = [] scene_lists = {} node_links = {} project_accepted_types = [ 'SplashImageNodeType', 'SplashMeshNodeType', 'SplashObjectNodeType' ] def execute(self, context): objectIsEdited = bpy.context.edit_object is not None if objectIsEdited is True: bpy.ops.object.editmode_toggle() self.scene_order.clear() self.scene_lists.clear() self.node_links.clear() for nodeTree in bpy.data.node_groups: nodeIndex = nodeTree.nodes.find(self.node_name) if nodeIndex != -1: node = nodeTree.nodes[nodeIndex] break self.world_node = node connectedScenes = [ socket.links[0].from_node for socket in node.inputs if socket.is_linked ] for scene in connectedScenes: scene_list = {} node_links = [] tree_valid, tree_error = self.parseTree(scene, scene_list, node_links, self.export_project) if not tree_valid: message = "Splash tree exporting error: " + tree_error print(message) return {'CANCELLED'} print(tree_error) self.scene_order.append(scene.name) self.scene_lists[scene.name] = scene_list self.node_links[scene.name] = node_links # If we only wanted to export meshes, the previous loop did the job if self.export_only_nodes is True: for scene in self.scene_lists: for node in self.scene_lists[scene]: self.scene_lists[scene][node].exportProperties( self.filepath) # Merge scenes info if exporting a project if self.export_project and len(self.scene_order) > 0: masterSceneName = self.scene_order[0] for sceneId in range(1, len(self.scene_order)): sceneName = self.scene_order[sceneId] for node in self.scene_lists[sceneName]: if node not in self.scene_lists[masterSceneName]: self.scene_lists[masterSceneName][ node] = self.scene_lists[sceneName][node] for link in self.node_links[sceneName]: self.node_links[masterSceneName].append(link) self.scene_order = [self.scene_order[0]] self.scene_lists = { masterSceneName: self.scene_lists[masterSceneName] } self.export(self.export_project) return {'FINISHED'} def parseTree(self, node, scene_list, node_links, export_project=False): node_valid, node_error = node.validate() if not node_valid: return node_valid, node_error if not export_project or node.bl_idname in self.project_accepted_types: scene_list[node.name] = node connectedNodes = [ socket.links[0].from_node for socket in node.inputs if socket.is_linked ] for connectedNode in connectedNodes: newLink = [connectedNode.name, node.name] if newLink not in node_links: node_links.append([connectedNode.name, node.name]) node_valid, node_error = self.parseTree(connectedNode, scene_list, node_links, export_project) if not node_valid: return node_valid, node_error return True, "Splash tree parsing successful" def export(self, export_project=False): file = open(self.filepath, "w", encoding="utf8", newline="\n") fw = file.write worldArgs = self.world_node.exportProperties(self.filepath) fw("// Splash configuration file\n" "// Exported with Blender Splash add-on\n" "{\n") if export_project: fw(" \"description\" : \"splashProject\",\n") else: fw(" \"description\" : \"splashConfiguration\",\n") # World informations fw(" \"world\" : {\n" " \"framerate\" : %i\n" " },\n" % (worldArgs['framerate'])) # Scenes list fw(" \"scenes\" : [\n") sceneIndex = 0 for scene in self.scene_order: # Find the Scene nodes for node in self.scene_lists[scene]: if self.scene_lists[scene][ node].bl_idname == "SplashSceneNodeType": args = self.scene_lists[scene][node].exportProperties( self.filepath) fw(" {\n") valueIndex = 0 for values in args: fw(" \"%s\" : %s" % (values, args[values])) if valueIndex < len(args) - 1: fw(",\n") else: fw("\n") valueIndex = valueIndex + 1 fw(" }") if sceneIndex < len(self.scene_lists) - 1: fw(",\n") else: fw("\n") sceneIndex = sceneIndex + 1 fw(" ],\n") # Scenes information sceneIndex = 0 for scene in self.scene_order: if not export_project: fw(" \"%s\" : {\n" % scene) for node in self.scene_lists[scene]: if self.scene_lists[scene][ node].bl_idname != "SplashSceneNodeType": args = self.scene_lists[scene][node].exportProperties( self.filepath) fw(" \"%s\" : {\n" % node) valueIndex = 0 for values in args: fw(" \"%s\" : %s" % (values, args[values])) if valueIndex < len(args) - 1: fw(",\n") else: fw("\n") valueIndex = valueIndex + 1 fw(" },\n") # Links fw(" \"links\" : [\n") linkIndex = 0 for link in self.node_links[scene]: fw(" [\"%s\", \"%s\"]" % (link[0], link[1])) if linkIndex < len(self.node_links[scene]) - 1: fw(",\n") else: fw("\n") linkIndex = linkIndex + 1 fw(" ]\n") if sceneIndex < len(self.scene_lists) - 1: fw(" },\n") else: fw(" }\n") sceneIndex = sceneIndex + 1 if not export_project: fw("}") def invoke(self, context, event): self.filepath = os.path.splitext(bpy.data.filepath)[0] + ".json" context.window_manager.fileselect_add(self) return {'RUNNING_MODAL'}
class OPS_OT_EditAttribute(Operator): bl_idname = 'nextr_debug.edit_attribute' bl_label = 'Edit attribute' bl_description = 'Edit attribute' path : StringProperty(name="Path", description="RNA path of the attribute") panel_name : StringProperty() panels : EnumProperty(name="Panel", items=[('outfits','Outfits','Outfits panel',0),('body','Body','Body Panel',1),('rig','Rig Layers','Rig Layers Panel',2)]) name : StringProperty(default='Default Value', name="Attribute's Name") attribute : {} visibility_value: IntProperty(name="Visibility Value", description="On which value of the variable show the attribute in the UI") visibility_variable : StringProperty(name='Varibale Name') def execute(self, context): o = get_edited_object(context) a = get_attribute_by_path(context,self.panel_name, self.path) if a: if 'visibility' in a: a['visibility']['variable'] = self.visibility_variable a['visibility']['value'] = self.visibility_value else: a['visibility'] = {'variable': self.visibility_variable, 'value': self.visibility_value} a['name'] = self.name a['path'] = self.path new_attributes = [] for attribute in o.data['nextrrig_attributes'][self.panel_name]: if attribute['path'] == self.path: new_attributes.append(a) else: new_attributes.append(attribute) o.data['nextrrig_attributes'][self.panel_name] = new_attributes return {'FINISHED'} def invoke(self, context, event): self.attribute = get_attribute_by_path(context, self.panel_name, self.path) if not self.attribute: return {"CANCELED"} # might work on this some day, now you need to the name manually # items = [('none', 'Always Visible', 'Attribute is going to be always visible',0)] # # self.variables_enum : EnumProperty(name="Variables", items=items) # o = get_edited_object(context) # for key,prop in enumerate(o.data['nextrrig_properties']): # name = prop # try: # name = getattr(bpy.types.Armature.nextrrig_properties[1]['type'],prop)[1]['name'] # except: # continue # items.append((prop, name, 'Variable used for visibility', key+1)) if 'visibility' in self.attribute: self.visibility_variable = self.attribute['visibility']['variable'] self.visibility_value = self.attribute['visibility']['value'] else: self.visibility_value = 0 self.visibility_variable = "" self.panels = self.panel_name self.name = self.attribute['name'] if self.attribute['name'] else "Default Value" return context.window_manager.invoke_props_dialog(self, width=750) def draw(self, context): box = self.layout.box() box.label(text=self.name, icon="PREFERENCES") box.prop(self, "name", emboss=True) box.prop(self, "path", text="Path", icon="RNA") box.prop(self, 'panels') box_visibility = box.box() box_visibility.label(text="Visibility") box_visibility.prop(self, "visibility_variable") box_visibility.prop(self, 'visibility_value') if 'synced' in self.attribute: if self.attribute['synced']: box_synced = box.box() box_synced.label(text="Synced attributes") for synced in self.attribute['synced']: row = box_synced.row(align=True) row.label(text=synced) op = row.operator(OPS_OT_RemoveSyncedAttribute.bl_idname, text="", icon="TRASH") op.path = self.path op.panel_name = self.panel_name op.attribute_path = synced
class SceneCoat3D(PropertyGroup): defaultfolder = StringProperty( name="FilePath", subtype="DIR_PATH", ) cursor_loc = FloatVectorProperty(name="Cursor_loc", description="location") exchangedir = StringProperty(name="FilePath", subtype="DIR_PATH") exchangefolder = StringProperty(name="FilePath", subtype="DIR_PATH") wasactive = StringProperty(name="Pass active object", ) import_box = BoolProperty(name="Import window", description="Allows to skip import dialog", default=True) exchange_found = BoolProperty( name="Exchange Found", description="Alert if Exchange folder is not found", default=True) export_box = BoolProperty(name="Export window", description="Allows to skip export dialog", default=True) export_color = BoolProperty(name="Export color", description="Export color texture", default=True) export_spec = BoolProperty(name="Export specular", description="Export specular texture", default=True) export_normal = BoolProperty(name="Export Normal", description="Export normal texture", default=True) export_disp = BoolProperty(name="Export Displacement", description="Export displacement texture", default=True) export_position = BoolProperty(name="Export Source Position", description="Export source position", default=True) export_zero_layer = BoolProperty( name="Export from Layer 0", description="Export mesh from Layer 0", default=True) export_coarse = BoolProperty(name="Export Coarse", description="Export Coarse", default=True) exportfile = BoolProperty(name="No Import File", description="Add Modifiers and export", default=False) importmod = BoolProperty(name="Remove Modifiers", description="Import and add modifiers", default=False) exportmod = BoolProperty(name="Modifiers", description="Export modifiers", default=False) export_pos = BoolProperty(name="Remember Position", description="Remember position", default=True) importtextures = BoolProperty(name="Bring Textures", description="Import Textures", default=True) importlevel = BoolProperty(name="Multires. Level", description="Bring Specific Multires Level", default=False) exportover = BoolProperty(name="Export Obj", description="Import Textures", default=False) importmesh = BoolProperty(name="Mesh", description="Import Mesh", default=True) # copy location cursor = FloatVectorProperty(name="Cursor", description="Location", subtype="XYZ", default=(0.0, 0.0, 0.0)) loca = FloatVectorProperty(name="location", description="Location", subtype="XYZ", default=(0.0, 0.0, 0.0)) rota = FloatVectorProperty(name="location", description="Location", subtype="EULER", default=(0.0, 0.0, 0.0)) scal = FloatVectorProperty(name="location", description="Location", subtype="XYZ", default=(0.0, 0.0, 0.0)) dime = FloatVectorProperty(name="dimension", description="Dimension", subtype="XYZ", default=(0.0, 0.0, 0.0)) type = EnumProperty(name="Export Type", description="Different Export Types", items=( ("ppp", "Per-Pixel Painting", ""), ("mv", "Microvertex Painting", ""), ("ptex", "Ptex Painting", ""), ("uv", "UV-Mapping", ""), ("ref", "Reference Mesh", ""), ("retopo", "Retopo mesh as new layer", ""), ("vox", "Mesh As Voxel Object", ""), ("alpha", "Mesh As New Pen Alpha", ""), ("prim", "Mesh As Voxel Primitive", ""), ("curv", "Mesh As a Curve Profile", ""), ("autopo", "Mesh For Auto-retopology", ""), ), default="ppp")
class NODETREE_SOURCE_lib_items(PropertyGroup): name: StringProperty()
class OctaneThinLensCameraGroupPosition(OctaneGroupTitleSocket): bl_idname = "OctaneThinLensCameraGroupPosition" bl_label = "[OctaneGroupTitle]Position" octane_group_sockets: StringProperty(name="Group Sockets", default="Position;Target;Up-vector;")
class ExportGLTF2_Base: # TODO: refactor to avoid boilerplate def __init__(self): from io_scene_gltf2.io.exp import gltf2_io_draco_compression_extension self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists( ) bl_options = {'UNDO', 'PRESET'} export_format: EnumProperty( name='Format', items= (('GLB', 'glTF Binary (.glb)', 'Exports a single file, with all data packed in binary form. ' 'Most efficient and portable, but more difficult to edit later'), ('GLTF_EMBEDDED', 'glTF Embedded (.gltf)', 'Exports a single file, with all data packed in JSON. ' 'Less efficient than binary, but easier to edit later'), ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)', 'Exports multiple files, with separate JSON, binary and texture data. ' 'Easiest to edit later')), description=( 'Output format and embedding options. Binary is most efficient, ' 'but JSON (embedded or separate) may be easier to edit later'), default='GLB') ui_tab: EnumProperty( items=(('GENERAL', "General", "General settings"), ('MESHES', "Meshes", "Mesh settings"), ('OBJECTS', "Objects", "Object settings"), ('ANIMATION', "Animation", "Animation settings")), name="ui_tab", description="Export setting categories", ) export_copyright: StringProperty( name='Copyright', description='Legal rights and conditions for the model', default='') export_image_format: EnumProperty( name='Images', items=( ('AUTO', 'Automatic', 'Save PNGs as PNGs and JPEGs as JPEGs.\n' 'If neither one, use PNG'), ('JPEG', 'JPEG Format (.jpg)', 'Save images as JPEGs. (Images that need alpha are saved as PNGs though.)\n' 'Be aware of a possible loss in quality'), ), description= ('Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web ' 'applications due to the smaller file size'), default='AUTO') export_texture_dir: StringProperty( name='Textures', description= 'Folder to place texture files in. Relative to the .gltf file', default='', ) export_texcoords: BoolProperty( name='UVs', description='Export UVs (texture coordinates) with meshes', default=True) export_normals: BoolProperty( name='Normals', description='Export vertex normals with meshes', default=True) export_draco_mesh_compression_enable: BoolProperty( name='Draco mesh compression', description='Compress mesh using Draco', default=False) export_draco_mesh_compression_level: IntProperty( name='Compression level', description= 'Compression level (0 = most speed, 6 = most compression, higher values currently not supported)', default=6, min=0, max=6) export_draco_position_quantization: IntProperty( name='Position quantization bits', description= 'Quantization bits for position values (0 = no quantization)', default=14, min=0, max=30) export_draco_normal_quantization: IntProperty( name='Normal quantization bits', description='Quantization bits for normal values (0 = no quantization)', default=10, min=0, max=30) export_draco_texcoord_quantization: IntProperty( name='Texcoord quantization bits', description= 'Quantization bits for texture coordinate values (0 = no quantization)', default=12, min=0, max=30) export_draco_generic_quantization: IntProperty( name='Generic quantization bits', description= 'Quantization bits for generic coordinate values like weights or joints (0 = no quantization)', default=12, min=0, max=30) export_tangents: BoolProperty( name='Tangents', description='Export vertex tangents with meshes', default=False) export_materials: BoolProperty(name='Materials', description='Export materials', default=True) export_colors: BoolProperty(name='Vertex Colors', description='Export vertex colors with meshes', default=True) export_cameras: BoolProperty(name='Cameras', description='Export cameras', default=False) export_selected: BoolProperty(name='Selected Objects', description='Export selected objects only', default=False) export_extras: BoolProperty( name='Custom Properties', description='Export custom properties as glTF extras', default=False) export_yup: BoolProperty(name='+Y Up', description='Export using glTF convention, +Y up', default=True) export_apply: BoolProperty( name='Apply Modifiers', description='Apply modifiers (excluding Armatures) to mesh objects -' 'WARNING: prevents exporting shape keys', default=False) export_animations: BoolProperty( name='Animations', description='Exports active actions and NLA tracks as glTF animations', default=True) export_frame_range: BoolProperty( name='Limit to Playback Range', description='Clips animations to selected playback range', default=True) export_frame_step: IntProperty( name='Sampling Rate', description='How often to evaluate animated values (in frames)', default=1, min=1, max=120) export_force_sampling: BoolProperty( name='Always Sample Animations', description='Apply sampling to all animations', default=True) export_nla_strips: BoolProperty(name='NLA Strips', description='Export NLA Strip animations', default=True) export_def_bones: BoolProperty( name='Export Deformation bones only', description= 'Export Deformation bones only (and needed bones for hierarchy)', default=False) export_current_frame: BoolProperty( name='Use Current Frame', description='Export the scene in the current animation frame', default=False) export_skins: BoolProperty(name='Skinning', description='Export skinning (armature) data', default=True) export_all_influences: BoolProperty( name='Include All Bone Influences', description= 'Allow >4 joint vertex influences. Models may appear incorrectly in many viewers', default=False) export_morph: BoolProperty(name='Shape Keys', description='Export shape keys (morph targets)', default=True) export_morph_normal: BoolProperty( name='Shape Key Normals', description='Export vertex normals with shape keys (morph targets)', default=True) export_morph_tangent: BoolProperty( name='Shape Key Tangents', description='Export vertex tangents with shape keys (morph targets)', default=False) export_lights: BoolProperty( name='Punctual Lights', description='Export directional, point, and spot lights. ' 'Uses "KHR_lights_punctual" glTF extension', default=False) export_displacement: BoolProperty( name='Displacement Textures (EXPERIMENTAL)', description='EXPERIMENTAL: Export displacement textures. ' 'Uses incomplete "KHR_materials_displacement" glTF extension', default=False) will_save_settings: BoolProperty( name='Remember Export Settings', description='Store glTF export settings in the Blender project', default=False) # Custom scene property for saving settings scene_key = "glTF2ExportSettings" # def invoke(self, context, event): settings = context.scene.get(self.scene_key) self.will_save_settings = False self.has_active_extenions = False if settings: try: for (k, v) in settings.items(): setattr(self, k, v) self.will_save_settings = True except (AttributeError, TypeError): self.report({ "ERROR" }, "Loading export settings failed. Removed corrupted settings" ) del context.scene[self.scene_key] import sys preferences = bpy.context.preferences for addon_name in preferences.addons.keys(): try: if hasattr(sys.modules[addon_name], 'glTF2ExportUserExtension') or hasattr( sys.modules[addon_name], 'glTF2ExportUserExtensions'): extension_panel_unregister_functors.append( sys.modules[addon_name].register_panel()) self.has_active_extenions = True except Exception: pass return ExportHelper.invoke(self, context, event) def save_settings(self, context): # find all export_ props all_props = self.properties export_props = { x: getattr(self, x) for x in dir(all_props) if x.startswith("export_") and all_props.get(x) is not None } context.scene[self.scene_key] = export_props def execute(self, context): import os import datetime from .blender.exp import gltf2_blender_export if self.will_save_settings: self.save_settings(context) if self.export_format == 'GLB': self.filename_ext = '.glb' else: self.filename_ext = '.gltf' # All custom export settings are stored in this container. export_settings = {} export_settings['timestamp'] = datetime.datetime.now() export_settings['gltf_filepath'] = bpy.path.ensure_ext( self.filepath, self.filename_ext) export_settings['gltf_filedirectory'] = os.path.dirname( export_settings['gltf_filepath']) + '/' export_settings['gltf_texturedirectory'] = os.path.join( export_settings['gltf_filedirectory'], self.export_texture_dir, ) export_settings['gltf_format'] = self.export_format export_settings['gltf_image_format'] = self.export_image_format export_settings['gltf_copyright'] = self.export_copyright export_settings['gltf_texcoords'] = self.export_texcoords export_settings['gltf_normals'] = self.export_normals export_settings[ 'gltf_tangents'] = self.export_tangents and self.export_normals if self.is_draco_available: export_settings[ 'gltf_draco_mesh_compression'] = self.export_draco_mesh_compression_enable export_settings[ 'gltf_draco_mesh_compression_level'] = self.export_draco_mesh_compression_level export_settings[ 'gltf_draco_position_quantization'] = self.export_draco_position_quantization export_settings[ 'gltf_draco_normal_quantization'] = self.export_draco_normal_quantization export_settings[ 'gltf_draco_texcoord_quantization'] = self.export_draco_texcoord_quantization export_settings[ 'gltf_draco_generic_quantization'] = self.export_draco_generic_quantization else: export_settings['gltf_draco_mesh_compression'] = False export_settings['gltf_materials'] = self.export_materials export_settings['gltf_colors'] = self.export_colors export_settings['gltf_cameras'] = self.export_cameras export_settings['gltf_selected'] = self.export_selected export_settings['gltf_layers'] = True # self.export_layers export_settings['gltf_extras'] = self.export_extras export_settings['gltf_yup'] = self.export_yup export_settings['gltf_apply'] = self.export_apply export_settings['gltf_current_frame'] = self.export_current_frame export_settings['gltf_animations'] = self.export_animations if self.export_animations: export_settings['gltf_frame_range'] = self.export_frame_range export_settings['gltf_force_sampling'] = self.export_force_sampling if self.export_force_sampling: export_settings['gltf_def_bones'] = self.export_def_bones else: export_settings['gltf_def_bones'] = False export_settings['gltf_nla_strips'] = self.export_nla_strips else: export_settings['gltf_frame_range'] = False export_settings['gltf_move_keyframes'] = False export_settings['gltf_force_sampling'] = False export_settings['gltf_def_bones'] = False export_settings['gltf_skins'] = self.export_skins if self.export_skins: export_settings[ 'gltf_all_vertex_influences'] = self.export_all_influences else: export_settings['gltf_all_vertex_influences'] = False export_settings['gltf_frame_step'] = self.export_frame_step export_settings['gltf_morph'] = self.export_morph if self.export_morph: export_settings['gltf_morph_normal'] = self.export_morph_normal else: export_settings['gltf_morph_normal'] = False if self.export_morph and self.export_morph_normal: export_settings['gltf_morph_tangent'] = self.export_morph_tangent else: export_settings['gltf_morph_tangent'] = False export_settings['gltf_lights'] = self.export_lights export_settings['gltf_displacement'] = self.export_displacement export_settings['gltf_binary'] = bytearray() export_settings['gltf_binaryfilename'] = os.path.splitext( os.path.basename( bpy.path.ensure_ext(self.filepath, self.filename_ext)))[0] + '.bin' user_extensions = [] import sys preferences = bpy.context.preferences for addon_name in preferences.addons.keys(): try: module = sys.modules[addon_name] except Exception: continue if hasattr(module, 'glTF2ExportUserExtension'): extension_ctor = module.glTF2ExportUserExtension user_extensions.append(extension_ctor()) if hasattr(module, 'glTF2ExportUserExtensions'): extension_ctors = module.glTF2ExportUserExtensions for extension_ctor in extension_ctors: user_extensions.append(extension_ctor()) export_settings['gltf_user_extensions'] = user_extensions return gltf2_blender_export.save(context, export_settings) def draw(self, context): pass # Is needed to get panels available
class OctaneThinLensCamera(bpy.types.Node, OctaneBaseNode): bl_idname = "OctaneThinLensCamera" bl_label = "Thin lens camera" bl_width_default = 200 octane_render_pass_id = -1 octane_render_pass_name = "" octane_render_pass_short_name = "" octane_render_pass_description = "" octane_render_pass_sub_type_name = "" octane_min_version = 0 octane_node_type: IntProperty(name="Octane Node Type", default=13) octane_socket_list: StringProperty( name="Socket List", default= "Orthographic;Sensor width;Focal length;F-stop;Field of view;Scale of view;Distortion;Lens shift;Perspective correction;Pixel aspect ratio;Near clip depth;Far clip depth;Auto-focus;Focal depth;Aperture;Aperture aspect ratio;Aperture edge;Bokeh side count;Bokeh rotation;Bokeh roundedness;Position;Target;Up-vector;Stereo output;Stereo mode;Eye distance;Swap eyes;Left stereo filter;Right stereo filter;Anaglyphic stereo;" ) octane_attribute_list: StringProperty( name="Attribute List", default="a_load_initial_state;a_save_initial_state;") octane_attribute_config_list: StringProperty(name="Attribute Config List", default="1;1;") octane_static_pin_count: IntProperty(name="Octane Static Pin Count", default=30) a_load_initial_state: BoolProperty( name="Load initial state", default=False, update=None, description= "If enabled and the node gets evaluated, the camera is reset to the previously saved position and orientation" ) a_save_initial_state: BoolProperty( name="Save initial state", default=True, update=None, description= "If enabled and the node gets evaluated, the current camera position and orientation will be saved" ) def init(self, context): self.inputs.new("OctaneThinLensCameraOrthographic", OctaneThinLensCameraOrthographic.bl_label).init() self.inputs.new( "OctaneThinLensCameraGroupPhysicalCameraParameters", OctaneThinLensCameraGroupPhysicalCameraParameters.bl_label).init() self.inputs.new("OctaneThinLensCameraSensorWidth", OctaneThinLensCameraSensorWidth.bl_label).init() self.inputs.new("OctaneThinLensCameraFocalLength", OctaneThinLensCameraFocalLength.bl_label).init() self.inputs.new("OctaneThinLensCameraFstop", OctaneThinLensCameraFstop.bl_label).init() self.inputs.new("OctaneThinLensCameraGroupViewingAngle", OctaneThinLensCameraGroupViewingAngle.bl_label).init() self.inputs.new("OctaneThinLensCameraFov", OctaneThinLensCameraFov.bl_label).init() self.inputs.new("OctaneThinLensCameraScale", OctaneThinLensCameraScale.bl_label).init() self.inputs.new("OctaneThinLensCameraDistortion", OctaneThinLensCameraDistortion.bl_label).init() self.inputs.new("OctaneThinLensCameraLensShift", OctaneThinLensCameraLensShift.bl_label).init() self.inputs.new( "OctaneThinLensCameraPerspectiveCorrection", OctaneThinLensCameraPerspectiveCorrection.bl_label).init() self.inputs.new("OctaneThinLensCameraPixelAspectRatio", OctaneThinLensCameraPixelAspectRatio.bl_label).init() self.inputs.new("OctaneThinLensCameraGroupClipping", OctaneThinLensCameraGroupClipping.bl_label).init() self.inputs.new("OctaneThinLensCameraNearClipDepth", OctaneThinLensCameraNearClipDepth.bl_label).init() self.inputs.new("OctaneThinLensCameraFarClipDepth", OctaneThinLensCameraFarClipDepth.bl_label).init() self.inputs.new("OctaneThinLensCameraGroupDepthOfField", OctaneThinLensCameraGroupDepthOfField.bl_label).init() self.inputs.new("OctaneThinLensCameraAutofocus", OctaneThinLensCameraAutofocus.bl_label).init() self.inputs.new("OctaneThinLensCameraFocalDepth", OctaneThinLensCameraFocalDepth.bl_label).init() self.inputs.new("OctaneThinLensCameraAperture", OctaneThinLensCameraAperture.bl_label).init() self.inputs.new( "OctaneThinLensCameraApertureAspectRatio", OctaneThinLensCameraApertureAspectRatio.bl_label).init() self.inputs.new("OctaneThinLensCameraApertureEdge", OctaneThinLensCameraApertureEdge.bl_label).init() self.inputs.new("OctaneThinLensCameraBokehSidecount", OctaneThinLensCameraBokehSidecount.bl_label).init() self.inputs.new("OctaneThinLensCameraBokehRotation", OctaneThinLensCameraBokehRotation.bl_label).init() self.inputs.new("OctaneThinLensCameraBokehRoundedness", OctaneThinLensCameraBokehRoundedness.bl_label).init() self.inputs.new("OctaneThinLensCameraGroupPosition", OctaneThinLensCameraGroupPosition.bl_label).init() self.inputs.new("OctaneThinLensCameraPos", OctaneThinLensCameraPos.bl_label).init() self.inputs.new("OctaneThinLensCameraTarget", OctaneThinLensCameraTarget.bl_label).init() self.inputs.new("OctaneThinLensCameraUp", OctaneThinLensCameraUp.bl_label).init() self.inputs.new("OctaneThinLensCameraGroupStereo", OctaneThinLensCameraGroupStereo.bl_label).init() self.inputs.new("OctaneThinLensCameraStereoOutput", OctaneThinLensCameraStereoOutput.bl_label).init() self.inputs.new("OctaneThinLensCameraStereoMode", OctaneThinLensCameraStereoMode.bl_label).init() self.inputs.new("OctaneThinLensCameraStereodist", OctaneThinLensCameraStereodist.bl_label).init() self.inputs.new("OctaneThinLensCameraStereoSwitchEyes", OctaneThinLensCameraStereoSwitchEyes.bl_label).init() self.inputs.new("OctaneThinLensCameraLeftFilter", OctaneThinLensCameraLeftFilter.bl_label).init() self.inputs.new("OctaneThinLensCameraRightFilter", OctaneThinLensCameraRightFilter.bl_label).init() self.inputs.new("OctaneThinLensCameraStereo", OctaneThinLensCameraStereo.bl_label).init() self.outputs.new("OctaneCameraOutSocket", "Camera out").init()
class PIX_CSV_Operator(bpy.types.Operator): # Plugin definitions, such as ID, name, and file extension filters bl_idname = "object.pix_csv_importer" bl_label = "Import PIX CSV" filepath = StringProperty(subtype = "FILE_PATH") filter_glob = StringProperty(default = "*.csv", options = {'HIDDEN'}) # Options for generation of vertices mirror_x = BoolProperty( name = "Mirror X", description = "Mirror all the vertices across X axis", default = True, ) vertex_order = BoolProperty( name = "Change vertex order", description = "Reorder vertices in counter-clockwise order", default = True, ) # Options for axis alignment axis_forward = EnumProperty( name = "Forward", items = ( ('X', "X Forward", ""), ('Y', "Y Forward", ""), ('Z', "Z Forward", ""), ('-X', "-X Forward", ""), ('-Y', "-Y Forward", ""), ('-Z', "-Z Forward", ""), ), default = 'Z', ) axis_up = EnumProperty( name = "Up", items = ( ('X', "X Up", ""), ('Y', "Y Up", ""), ('Z', "Z Up", ""), ('-X', "-X Up", ""), ('-Y', "-Y Up", ""), ('-Z', "-Z Up", ""), ), default = 'Y', ) # ~~~~~~~~~~~~~~~~~~~~Operator Functions~~~~~~~~~~~~~~~~~~~~ def execute(self, context): keywords = self.as_keywords(ignore = ("axis_forward", "axis_up", "filter_glob")) global_matrix = axis_conversion(from_forward = self.axis_forward, from_up = self.axis_up).to_4x4() keywords["global_matrix"] = global_matrix print(keywords) importCSV(**keywords) return {'FINISHED'} def invoke(self, context, event): context.window_manager.fileselect_add(self) return {'RUNNING_MODAL'} def draw(self, context): layout = self.layout col = layout.column() col.label(text = "Import Options") row = col.row() row.prop(self, "mirror_x") row = col.row() row.prop(self, "vertex_order") layout.prop(self, "axis_forward") layout.prop(self, "axis_up")
class OctaneVolumetricSpotlight(bpy.types.Node, OctaneBaseNode): bl_idname = "OctaneVolumetricSpotlight" bl_label = "Volumetric spotlight" bl_width_default = 200 octane_render_pass_id = -1 octane_render_pass_name = "" octane_render_pass_short_name = "" octane_render_pass_description = "" octane_render_pass_sub_type_name = "" octane_min_version = 0 octane_node_type: IntProperty(name="Octane Node Type", default=152) octane_socket_list: StringProperty( name="Socket List", default= "Throw distance;Cone width;Light medium;Emitter material;Barn doors material;Object layer;Light transform;Enable barn doors;Barn doors size;Barn door 1 angle;Barn door 2 angle;Barn door 3 angle;Barn door 4 angle;" ) octane_attribute_list: StringProperty(name="Attribute List", default="") octane_attribute_config_list: StringProperty(name="Attribute Config List", default="") octane_static_pin_count: IntProperty(name="Octane Static Pin Count", default=13) def init(self, context): self.inputs.new( "OctaneVolumetricSpotlightThrowDistance", OctaneVolumetricSpotlightThrowDistance.bl_label).init() self.inputs.new("OctaneVolumetricSpotlightConeWidth", OctaneVolumetricSpotlightConeWidth.bl_label).init() self.inputs.new("OctaneVolumetricSpotlightMedium", OctaneVolumetricSpotlightMedium.bl_label).init() self.inputs.new( "OctaneVolumetricSpotlightEmitterMaterial", OctaneVolumetricSpotlightEmitterMaterial.bl_label).init() self.inputs.new( "OctaneVolumetricSpotlightBarnDoorsMaterial", OctaneVolumetricSpotlightBarnDoorsMaterial.bl_label).init() self.inputs.new("OctaneVolumetricSpotlightObjectLayer", OctaneVolumetricSpotlightObjectLayer.bl_label).init() self.inputs.new("OctaneVolumetricSpotlightTransform", OctaneVolumetricSpotlightTransform.bl_label).init() self.inputs.new( "OctaneVolumetricSpotlightGroupBarnDoors", OctaneVolumetricSpotlightGroupBarnDoors.bl_label).init() self.inputs.new( "OctaneVolumetricSpotlightEnableBarnDoors", OctaneVolumetricSpotlightEnableBarnDoors.bl_label).init() self.inputs.new( "OctaneVolumetricSpotlightBarnDoorsSize", OctaneVolumetricSpotlightBarnDoorsSize.bl_label).init() self.inputs.new( "OctaneVolumetricSpotlightBarnDoor1Angle", OctaneVolumetricSpotlightBarnDoor1Angle.bl_label).init() self.inputs.new( "OctaneVolumetricSpotlightBarnDoor2Angle", OctaneVolumetricSpotlightBarnDoor2Angle.bl_label).init() self.inputs.new( "OctaneVolumetricSpotlightBarnDoor3Angle", OctaneVolumetricSpotlightBarnDoor3Angle.bl_label).init() self.inputs.new( "OctaneVolumetricSpotlightBarnDoor4Angle", OctaneVolumetricSpotlightBarnDoor4Angle.bl_label).init() self.outputs.new("OctaneGeometryOutSocket", "Geometry out").init()
class SvGenFloatRange(bpy.types.Node, SverchCustomTreeNode): ''' Generator range list of floats''' bl_idname = 'SvGenFloatRange' bl_label = 'Range Float' bl_icon = 'IPO_LINEAR' start_: FloatProperty(name='start', description='start', default=0, update=updateNode) stop_: FloatProperty(name='stop', description='stop', default=10, update=updateNode) count_: IntProperty(name='count', description='num items', default=10, min=1, update=updateNode) step_: FloatProperty(name='step', description='step', default=1.0, update=updateNode) current_mode: StringProperty(default="FRANGE") modes = [ ("FRANGE", "Range", "Series based frange like function", 1), ("FRANGE_COUNT", "Count", "Create series based on count", 2), ("FRANGE_STEP", "Step", "Create range based step and count", 3), ] def mode_change(self, context): # just because click doesn't mean we need to change mode mode = self.mode if mode == self.current_mode: return if mode == 'FRANGE': self.inputs[1].prop_name = 'stop_' self.inputs[2].prop_name = 'step_' elif mode == 'FRANGE_COUNT': self.inputs[1].prop_name = 'stop_' self.inputs[2].prop_name = 'count_' else: self.inputs[1].prop_name = 'step_' self.inputs[2].prop_name = 'count_' self.current_mode = mode updateNode(self, context) mode: EnumProperty(items=modes, default='FRANGE', update=mode_change) def sv_init(self, context): self.inputs.new('SvStringsSocket', "Start").prop_name = 'start_' self.inputs.new('SvStringsSocket', "Step").prop_name = 'stop_' self.inputs.new('SvStringsSocket', "Stop").prop_name = 'step_' self.outputs.new('SvStringsSocket', "Range") def draw_buttons(self, context, layout): layout.prop(self, "mode", expand=True) func_dict = { 'FRANGE': frange, 'FRANGE_COUNT': frange_count, 'FRANGE_STEP': frange_step } def process(self): inputs = self.inputs outputs = self.outputs if not outputs[0].is_linked: return param = [inputs[i].sv_get()[0] for i in range(3)] f = self.func_dict[self.mode] out = [list(f(*args)) for args in zip(*match_long_repeat(param))] outputs['Range'].sv_set(out)
class WebAuth(Operator): bl_idname = 'bis.web_auth' bl_label = 'Authorization' userLogin: StringProperty(name='Login', description='User Login', default='') userPassword: StringProperty(subtype='PASSWORD', name='Password', description='User Password', default='') userStayLogged: BoolProperty(name='Stay logged (insecure)', description='Stay logged', default=False) def execute(self, context): if WebAuthVars.logged: __class__.log_off(context=context) else: self.log_in(context=context) for area in context.screen.areas: area.tag_redraw() return {'FINISHED'} def invoke(self, context, event): if WebAuthVars.logged: return self.execute(context) else: if WebAuthVars.userLogin: self.userLogin = WebAuthVars.userLogin return context.window_manager.invoke_props_dialog(self) @classmethod def get_init_data(cls, context): WebAuthVars.logged = False WebAuthVars.userStayLogged = False with open( os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json')) as currentFile: json_data = json.load(currentFile) WebAuthVars.host = json_data['host'] WebAuthVars.requestBase = json_data['requestbase'] if 'userLogin' in json_data: WebAuthVars.userLogin = json_data['userLogin'] else: WebAuthVars.userLogin = '' if 'token' in json_data: WebAuthVars.token = json_data['token'] else: WebAuthVars.token = '' currentFile.close() if WebAuthVars.token: cls.log_in(cls, context=context) def log_in(self, context): if WebAuthVars.token: if __class__.check_token_valid(context=context, user_login=WebAuthVars.userLogin, token=WebAuthVars.token): WebAuthVars.logged = True else: __class__.log_off(context=context) else: request = WebRequest.send_request(context=context, data={ 'userlogin': self.userLogin, 'userpassword': self.userPassword }, host_target='blender_auth') self.userPassword = '' if request: request_rez = json.loads(request.text) if request_rez['stat'] == 'OK': WebAuthVars.logged = True WebAuthVars.token = request_rez['data']['token'] WebAuthVars.userLogin = self.userLogin WebAuthVars.userProStatus = request_rez['data'][ 'prostatus'] __class__.save_config( user_login=WebAuthVars.userLogin, token=WebAuthVars.token if self.userStayLogged else '') else: bpy.ops.bis.messagebox('INVOKE_DEFAULT', message=request_rez['data']['text']) __class__.log_off(context=context) @staticmethod def log_off(context): WebAuthVars.token = '' WebAuthVars.logged = False WebRequestsVars.close_session() __class__.save_config(user_login=WebAuthVars.userLogin) @staticmethod def check_token_valid(context, user_login='', token=''): request = WebRequest.send_request(context=context, data={ 'userlogin': user_login, 'token': token }, host_target='blender_auth') if request: request_rez = json.loads(request.text) if request_rez['stat'] == 'OK': WebAuthVars.userProStatus = request_rez['data']['prostatus'] return True return False @staticmethod def save_config(user_login='', token=''): with open( os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json'), 'r+') as configFile: json_data = json.load(configFile) json_data['token'] = token json_data['userLogin'] = user_login configFile.seek(0) configFile.truncate() json.dump(json_data, configFile, indent=4) configFile.close()
def register(): bpy.utils.register_module(__name__) bpy.types.Scene.iskeyfree_data = StringProperty( name="Key", maxlen=32, description="Shortcut to verify") bpy.types.Scene.iskeyfree_use_crtl = BoolProperty( name="Ctrl", description="Ctrl key used in shortcut", default=False) bpy.types.Scene.iskeyfree_use_alt = BoolProperty( name="Alt", description="Alt key used in shortcut", default=False) bpy.types.Scene.iskeyfree_use_shift = BoolProperty( name="Shift", description="Shift key used in shortcut", default=False) bpy.types.Scene.iskeyfree_use_oskey = BoolProperty( name="OsKey", description="Operating system key used in shortcut", default=False) bpy.types.Scene.iskeyfree_numpad = EnumProperty( items=(('NONE', "Select key", ""), ("LEFTMOUSE", "LEFTMOUSE", ""), ("MIDDLEMOUSE", "MIDDLEMOUSE", ""), ("RIGHTMOUSE", "RIGHTMOUSE", ""), ("BUTTON4MOUSE", "BUTTON4MOUSE", ""), ("BUTTON5MOUSE", "BUTTON5MOUSE", ""), ("BUTTON6MOUSE", "BUTTON6MOUSE", ""), ("BUTTON7MOUSE", "BUTTON7MOUSE", ""), ("ACTIONMOUSE", "ACTIONMOUSE", ""), ("SELECTMOUSE", "SELECTMOUSE", ""), ("MOUSEMOVE", "MOUSEMOVE", ""), ("INBETWEEN_MOUSEMOVE", "INBETWEEN_MOUSEMOVE", ""), ("TRACKPADPAN", "TRACKPADPAN", ""), ("TRACKPADZOOM", "TRACKPADZOOM", ""), ("MOUSEROTATE", "MOUSEROTATE", ""), ("WHEELUPMOUSE", "WHEELUPMOUSE", ""), ("WHEELDOWNMOUSE", "WHEELDOWNMOUSE", ""), ("WHEELINMOUSE", "WHEELINMOUSE", ""), ("WHEELOUTMOUSE", "WHEELOUTMOUSE", ""), ("EVT_TWEAK_L", "EVT_TWEAK_L", ""), ("EVT_TWEAK_M", "EVT_TWEAK_M", ""), ("EVT_TWEAK_R", "EVT_TWEAK_R", ""), ("EVT_TWEAK_A", "EVT_TWEAK_A", ""), ("EVT_TWEAK_S", "EVT_TWEAK_S", ""), ("A", "A", ""), ("B", "B", ""), ("C", "C", ""), ("D", "D", ""), ("E", "E", ""), ("F", "F", ""), ("G", "G", ""), ("H", "H", ""), ("I", "I", ""), ("J", "J", ""), ("K", "K", ""), ("L", "L", ""), ("M", "M", ""), ("N", "N", ""), ("O", "O", ""), ("P", "P", ""), ("Q", "Q", ""), ("R", "R", ""), ("S", "S", ""), ("T", "T", ""), ("U", "U", ""), ("V", "V", ""), ("W", "W", ""), ("X", "X", ""), ("Y", "Y", ""), ("Z", "Z", ""), ("ZERO", "ZERO", ""), ("ONE", "ONE", ""), ("TWO", "TWO", ""), ("THREE", "THREE", ""), ("FOUR", "FOUR", ""), ("FIVE", "FIVE", ""), ("SIX", "SIX", ""), ("SEVEN", "SEVEN", ""), ("EIGHT", "EIGHT", ""), ("NINE", "NINE", ""), ("LEFT_CTRL", "LEFT_CTRL", ""), ("LEFT_ALT", "LEFT_ALT", ""), ("LEFT_SHIFT", "LEFT_SHIFT", ""), ("RIGHT_ALT", "RIGHT_ALT", ""), ("RIGHT_CTRL", "RIGHT_CTRL", ""), ("RIGHT_SHIFT", "RIGHT_SHIFT", ""), ("OSKEY", "OSKEY", ""), ("GRLESS", "GRLESS", ""), ("ESC", "ESC", ""), ("TAB", "TAB", ""), ("RET", "RET", ""), ("SPACE", "SPACE", ""), ("LINE_FEED", "LINE_FEED", ""), ("BACK_SPACE", "BACK_SPACE", ""), ("DEL", "DEL", ""), ("SEMI_COLON", "SEMI_COLON", ""), ("PERIOD", "PERIOD", ""), ("COMMA", "COMMA", ""), ("QUOTE", "QUOTE", ""), ("ACCENT_GRAVE", "ACCENT_GRAVE", ""), ("MINUS", "MINUS", ""), ("SLASH", "SLASH", ""), ("BACK_SLASH", "BACK_SLASH", ""), ("EQUAL", "EQUAL", ""), ("LEFT_BRACKET", "LEFT_BRACKET", ""), ("RIGHT_BRACKET", "RIGHT_BRACKET", ""), ("LEFT_ARROW", "LEFT_ARROW", ""), ("DOWN_ARROW", "DOWN_ARROW", ""), ("RIGHT_ARROW", "RIGHT_ARROW", ""), ("UP_ARROW", "UP_ARROW", ""), ("NUMPAD_1", "NUMPAD_1", ""), ("NUMPAD_2", "NUMPAD_2", ""), ("NUMPAD_3", "NUMPAD_3", ""), ("NUMPAD_4", "NUMPAD_4", ""), ("NUMPAD_5", "NUMPAD_5", ""), ("NUMPAD_6", "NUMPAD_6", ""), ("NUMPAD_7", "NUMPAD_7", ""), ("NUMPAD_8", "NUMPAD_8", ""), ("NUMPAD_9", "NUMPAD_9", ""), ("NUMPAD_0", "NUMPAD_0", ""), ("NUMPAD_PERIOD", "NUMPAD_PERIOD", ""), ("NUMPAD_SLASH", "NUMPAD_SLASH", ""), ("NUMPAD_ASTERIX", "NUMPAD_ASTERIX", ""), ("NUMPAD_MINUS", "NUMPAD_MINUS", ""), ("NUMPAD_ENTER", "NUMPAD_ENTER", ""), ("NUMPAD_PLUS", "NUMPAD_PLUS", ""), ("F1", "F1", ""), ("F2", "F2", ""), ("F3", "F3", ""), ("F4", "F4", ""), ("F5", "F5", ""), ("F6", "F6", ""), ("F7", "F7", ""), ("F8", "F8", ""), ("F9", "F9", ""), ("F10", "F10", ""), ("F11", "F11", ""), ("F12", "F12", ""), ("F13", "F13", ""), ("F14", "F14", ""), ("F15", "F15", ""), ("F16", "F16", ""), ("F17", "F17", ""), ("F18", "F18", ""), ("F19", "F19", ""), ("PAUSE", "PAUSE", ""), ("INSERT", "INSERT", ""), ("HOME", "HOME", ""), ("PAGE_UP", "PAGE_UP", ""), ("PAGE_DOWN", "PAGE_DOWN", ""), ("END", "END", ""), ("MEDIA_PLAY", "MEDIA_PLAY", ""), ("MEDIA_STOP", "MEDIA_STOP", ""), ("MEDIA_FIRST", "MEDIA_FIRST", ""), ("MEDIA_LAST", "MEDIA_LAST", ""), ("TEXTINPUT", "TEXTINPUT", ""), ("WINDOW_DEACTIVATE", "WINDOW_DEACTIVATE", ""), ("TIMER", "TIMER", ""), ("TIMER0", "TIMER0", ""), ("TIMER1", "TIMER1", ""), ("TIMER2", "TIMER2", ""), ("TIMER_JOBS", "TIMER_JOBS", ""), ("TIMER_AUTOSAVE", "TIMER_AUTOSAVE", ""), ("TIMER_REPORT", "TIMER_REPORT", ""), ("TIMERREGION", "TIMERREGION", ""), ("NDOF_MOTION", "NDOF_MOTION", ""), ("NDOF_BUTTON_MENU", "NDOF_BUTTON_MENU", ""), ("NDOF_BUTTON_FIT", "NDOF_BUTTON_FIT", ""), ("NDOF_BUTTON_TOP", "NDOF_BUTTON_TOP", ""), ("NDOF_BUTTON_BOTTOM", "NDOF_BUTTON_BOTTOM", ""), ("NDOF_BUTTON_LEFT", "NDOF_BUTTON_LEFT", ""), ("NDOF_BUTTON_RIGHT", "NDOF_BUTTON_RIGHT", ""), ("NDOF_BUTTON_FRONT", "NDOF_BUTTON_FRONT", ""), ("NDOF_BUTTON_BACK", "NDOF_BUTTON_BACK", ""), ("NDOF_BUTTON_ISO1", "NDOF_BUTTON_ISO1", ""), ("NDOF_BUTTON_ISO2", "NDOF_BUTTON_ISO2", ""), ("NDOF_BUTTON_ROLL_CW", "NDOF_BUTTON_ROLL_CW", ""), ("NDOF_BUTTON_ROLL_CCW", "NDOF_BUTTON_ROLL_CCW", ""), ("NDOF_BUTTON_SPIN_CW", "NDOF_BUTTON_SPIN_CW", ""), ("NDOF_BUTTON_SPIN_CCW", "NDOF_BUTTON_SPIN_CCW", ""), ("NDOF_BUTTON_TILT_CW", "NDOF_BUTTON_TILT_CW", ""), ("NDOF_BUTTON_TILT_CCW", "NDOF_BUTTON_TILT_CCW", ""), ("NDOF_BUTTON_ROTATE", "NDOF_BUTTON_ROTATE", ""), ("NDOF_BUTTON_PANZOOM", "NDOF_BUTTON_PANZOOM", ""), ("NDOF_BUTTON_DOMINANT", "NDOF_BUTTON_DOMINANT", ""), ("NDOF_BUTTON_PLUS", "NDOF_BUTTON_PLUS", ""), ("NDOF_BUTTON_MINUS", "NDOF_BUTTON_MINUS", ""), ("NDOF_BUTTON_ESC", "NDOF_BUTTON_ESC", ""), ("NDOF_BUTTON_ALT", "NDOF_BUTTON_ALT", ""), ("NDOF_BUTTON_SHIFT", "NDOF_BUTTON_SHIFT", ""), ("NDOF_BUTTON_CTRL", "NDOF_BUTTON_CTRL", ""), ("NDOF_BUTTON_1", "NDOF_BUTTON_1", ""), ("NDOF_BUTTON_2", "NDOF_BUTTON_2", ""), ("NDOF_BUTTON_3", "NDOF_BUTTON_3", ""), ("NDOF_BUTTON_4", "NDOF_BUTTON_4", ""), ("NDOF_BUTTON_5", "NDOF_BUTTON_5", ""), ("NDOF_BUTTON_6", "NDOF_BUTTON_6", ""), ("NDOF_BUTTON_7", "NDOF_BUTTON_7", ""), ("NDOF_BUTTON_8", "NDOF_BUTTON_8", ""), ("NDOF_BUTTON_9", "NDOF_BUTTON_9", ""), ("NDOF_BUTTON_10", "NDOF_BUTTON_10", ""), ("NDOF_BUTTON_A", "NDOF_BUTTON_A", ""), ("NDOF_BUTTON_B", "NDOF_BUTTON_B", ""), ("NDOF_BUTTON_C", "NDOF_BUTTON_C", "")), name="Quick Type", description="Enter key code in find text", update=update_data)
def register(): Scene = bpy.types.Scene Mat = bpy.types.Material Tex = bpy.types.Texture Obj = bpy.types.Object Cam = bpy.types.Camera Text = bpy.types.Text ###########################SCENE################################## # File Options Scene.pov_tempfiles_enable = BoolProperty( name="Enable Tempfiles", description= "Enable the OS-Tempfiles. Otherwise set the path where to save the files", default=True) Scene.pov_deletefiles_enable = BoolProperty( name="Delete files", description="Delete files after rendering. Doesn't work with the image", default=True) Scene.pov_scene_name = StringProperty( name="Scene Name", description= "Name of POV-Ray scene to create. Empty name will use the name of the blend file", default="", maxlen=1024) Scene.pov_scene_path = StringProperty( name="Export scene path", # description="Path to directory where the exported scene (POV and INI) is created", # Bug in POV-Ray RC3 description="Path to directory where the files are created", default="", maxlen=1024, subtype="DIR_PATH") Scene.pov_renderimage_path = StringProperty( name="Rendered image path", description="Full path to directory where the rendered image is saved", default="", maxlen=1024, subtype="DIR_PATH") Scene.pov_list_lf_enable = BoolProperty( name="LF in lists", description= "Enable line breaks in lists (vectors and indices). Disabled: lists are exported in one line", default=True) # Not a real pov option, just to know if we should write Scene.pov_radio_enable = BoolProperty( name="Enable Radiosity", description="Enable POV-Rays radiosity calculation", default=False) Scene.pov_radio_display_advanced = BoolProperty( name="Advanced Options", description="Show advanced options", default=False) Scene.pov_media_enable = BoolProperty( name="Enable Media", description="Enable POV-Rays atmospheric media", default=False) Scene.pov_media_samples = IntProperty( name="Samples", description= "Number of samples taken from camera to first object encountered along ray path for media calculation", min=1, max=100, default=35) Scene.pov_media_color = FloatVectorProperty( name="Media Color", description="The atmospheric media color", subtype='COLOR', precision=4, step=0.01, min=0, soft_max=1, default=(0.001, 0.001, 0.001), options={'ANIMATABLE'}) Scene.pov_baking_enable = BoolProperty( name="Enable Baking", description="Enable POV-Rays texture baking", default=False) Scene.pov_indentation_character = EnumProperty( name="Indentation", description="Select the indentation type", items=(("0", "None", "No indentation"), ("1", "Tabs", "Indentation with tabs"), ("2", "Spaces", "Indentation with spaces")), default="2") Scene.pov_indentation_spaces = IntProperty( name="Quantity of spaces", description="The number of spaces for indentation", min=1, max=10, default=4) Scene.pov_comments_enable = BoolProperty( name="Enable Comments", description="Add comments to pov file", default=True) # Real pov options Scene.pov_command_line_switches = StringProperty( name="Command Line Switches", description= "Command line switches consist of a + (plus) or - (minus) sign, followed by one or more alphabetic characters and possibly a numeric value", default="", maxlen=500) Scene.pov_antialias_enable = BoolProperty( name="Anti-Alias", description="Enable Anti-Aliasing", default=True) Scene.pov_antialias_method = EnumProperty( name="Method", description= "AA-sampling method. Type 1 is an adaptive, non-recursive, super-sampling method. Type 2 is an adaptive and recursive super-sampling method", items=(("0", "non-recursive AA", "Type 1 Sampling in POV-Ray"), ("1", "recursive AA", "Type 2 Sampling in POV-Ray")), default="1") Scene.pov_antialias_depth = IntProperty( name="Antialias Depth", description="Depth of pixel for sampling", min=1, max=9, default=3) Scene.pov_antialias_threshold = FloatProperty( name="Antialias Threshold", description="Tolerance for sub-pixels", min=0.0, max=1.0, soft_min=0.05, soft_max=0.5, default=0.1) Scene.pov_jitter_enable = BoolProperty( name="Jitter", description= "Enable Jittering. Adds noise into the sampling process (it should be avoided to use jitter in animation)", default=True) Scene.pov_jitter_amount = FloatProperty(name="Jitter Amount", description="Amount of jittering", min=0.0, max=1.0, soft_min=0.01, soft_max=1.0, default=1.0) Scene.pov_antialias_gamma = FloatProperty( name="Antialias Gamma", description= "POV-Ray compares gamma-adjusted values for super sampling. Antialias Gamma sets the Gamma before comparison", min=0.0, max=5.0, soft_min=0.01, soft_max=2.5, default=2.5) Scene.pov_max_trace_level = IntProperty( name="Max Trace Level", description="Number of reflections/refractions allowed on ray path", min=1, max=256, default=5) Scene.pov_photon_spacing = FloatProperty( name="Spacing", description= "Average distance between photons on surfaces. half this get four times as many surface photons", min=0.001, max=1.000, soft_min=0.001, soft_max=1.000, default=0.005, precision=3) Scene.pov_photon_max_trace_level = IntProperty( name="Max Trace Level", description="Number of reflections/refractions allowed on ray path", min=1, max=256, default=5) Scene.pov_photon_adc_bailout = FloatProperty( name="ADC Bailout", description= "The adc_bailout for photons. Use adc_bailout = 0.01 / brightest_ambient_object for good results", min=0.0, max=1000.0, soft_min=0.0, soft_max=1.0, default=0.1, precision=3) Scene.pov_photon_gather_min = IntProperty( name="Gather Min", description="Minimum number of photons gathered for each point", min=1, max=256, default=20) Scene.pov_photon_gather_max = IntProperty( name="Gather Max", description="Maximum number of photons gathered for each point", min=1, max=256, default=100) Scene.pov_radio_adc_bailout = FloatProperty( name="ADC Bailout", description= "The adc_bailout for radiosity rays. Use adc_bailout = 0.01 / brightest_ambient_object for good results", min=0.0, max=1000.0, soft_min=0.0, soft_max=1.0, default=0.01, precision=3) Scene.pov_radio_always_sample = BoolProperty( name="Always Sample", description= "Only use the data from the pretrace step and not gather any new samples during the final radiosity pass", default=True) Scene.pov_radio_brightness = FloatProperty( name="Brightness", description= "Amount objects are brightened before being returned upwards to the rest of the system", min=0.0, max=1000.0, soft_min=0.0, soft_max=10.0, default=1.0) Scene.pov_radio_count = IntProperty( name="Ray Count", description= "Number of rays for each new radiosity value to be calculated (halton sequence over 1600)", min=1, max=10000, soft_max=1600, default=35) Scene.pov_radio_error_bound = FloatProperty( name="Error Bound", description= "One of the two main speed/quality tuning values, lower values are more accurate", min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default=1.8) Scene.pov_radio_gray_threshold = FloatProperty( name="Gray Threshold", description= "One of the two main speed/quality tuning values, lower values are more accurate", min=0.0, max=1.0, soft_min=0, soft_max=1, default=0.0) Scene.pov_radio_low_error_factor = FloatProperty( name="Low Error Factor", description= "Just enough samples is slightly blotchy. Low error changes error tolerance for less critical last refining pass", min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, default=0.5) # max_sample - not available yet Scene.pov_radio_media = BoolProperty( name="Media", description="Radiosity estimation can be affected by media", default=False) Scene.pov_radio_minimum_reuse = FloatProperty( name="Minimum Reuse", description= "Fraction of the screen width which sets the minimum radius of reuse for each sample point (At values higher than 2% expect errors)", min=0.0, max=1.0, soft_min=0.1, soft_max=0.1, default=0.015, precision=3) Scene.pov_radio_nearest_count = IntProperty( name="Nearest Count", description= "Number of old ambient values blended together to create a new interpolated value", min=1, max=20, default=5) Scene.pov_radio_normal = BoolProperty( name="Normals", description="Radiosity estimation can be affected by normals", default=False) Scene.pov_radio_recursion_limit = IntProperty( name="Recursion Limit", description= "how many recursion levels are used to calculate the diffuse inter-reflection", min=1, max=20, default=3) Scene.pov_radio_pretrace_start = FloatProperty( name="Pretrace Start", description= "Fraction of the screen width which sets the size of the blocks in the mosaic preview first pass", min=0.01, max=1.00, soft_min=0.02, soft_max=1.0, default=0.08) Scene.pov_radio_pretrace_end = FloatProperty( name="Pretrace End", description= "Fraction of the screen width which sets the size of the blocks in the mosaic preview last pass", min=0.001, max=1.00, soft_min=0.01, soft_max=1.00, default=0.04, precision=3) #############################MATERIAL###################################### Mat.pov_irid_enable = BoolProperty( name="Enable Iridescence", description= "Newton's thin film interference (like an oil slick on a puddle of water or the rainbow hues of a soap bubble.)", default=False) Mat.pov_mirror_use_IOR = BoolProperty( name="Correct Reflection", description= "Use same IOR as raytrace transparency to calculate mirror reflections. More physically correct", default=False) Mat.pov_mirror_metallic = BoolProperty( name="Metallic Reflection", description= "mirror reflections get colored as diffuse (for metallic materials)", default=False) Mat.pov_conserve_energy = BoolProperty( name="Conserve Energy", description= "Light transmitted is more correctly reduced by mirror reflections, also the sum of diffuse and translucency gets reduced below one ", default=True) Mat.pov_irid_amount = FloatProperty( name="amount", description= "Contribution of the iridescence effect to the overall surface color. As a rule of thumb keep to around 0.25 (25% contribution) or less, but experiment. If the surface is coming out too white, try lowering the diffuse and possibly the ambient values of the surface", min=0.0, max=1.0, soft_min=0.01, soft_max=1.0, default=0.25) Mat.pov_irid_thickness = FloatProperty( name="thickness", description= "A very thin film will have a high frequency of color changes while a thick film will have large areas of color", min=0.0, max=1000.0, soft_min=0.1, soft_max=10.0, default=1) Mat.pov_irid_turbulence = FloatProperty( name="turbulence", description="This parameter varies the thickness", min=0.0, max=10.0, soft_min=0.000, soft_max=1.0, default=0) Mat.pov_interior_fade_color = FloatVectorProperty( name="Fade Color", description="Color of filtered attenuation for transparent materials", subtype='COLOR', precision=4, step=0.01, min=0.0, soft_max=1.0, default=(0, 0, 0), options={'ANIMATABLE'}) Mat.pov_caustics_enable = BoolProperty( name="Caustics", description= "use only fake refractive caustics (default) or photon based reflective/refractive caustics", default=True) Mat.pov_fake_caustics = BoolProperty( name="Fake Caustics", description="use only (Fast) fake refractive caustics", default=True) Mat.pov_fake_caustics_power = FloatProperty( name="Fake caustics power", description= "Values typically range from 0.0 to 1.0 or higher. Zero is no caustics. Low, non-zero values give broad hot-spots while higher values give tighter, smaller simulated focal points", min=0.00, max=10.0, soft_min=0.00, soft_max=1.10, default=0.1) Mat.pov_photons_refraction = BoolProperty( name="Refractive Photon Caustics", description="more physically correct", default=False) Mat.pov_photons_dispersion = FloatProperty( name="chromatic dispersion", description= "Light passing through will be separated according to wavelength. This ratio of refractive indices for violet to red controls how much the colors are spread out 1 = no dispersion, good values are 1.01 to 1.1", min=1.0000, max=10.000, soft_min=1.0000, soft_max=1.1000, precision=4, default=1.0000) Mat.pov_photons_reflection = BoolProperty( name="Reflective Photon Caustics", description="Use this to make your Sauron's ring ;-P", default=False) Mat.pov_refraction_type = EnumProperty( items=[ ("0", "None", "use only reflective caustics"), ("1", "Fake Caustics", "use fake caustics"), ("2", "Photons Caustics", "use photons for refractive caustics"), ], name="Refractive", description= "use fake caustics (fast) or true photons for refractive Caustics", default="1") ##################################CustomPOV Code############################ Mat.pov_replacement_text = StringProperty( name="Declared name:", description= "Type the declared name in custom POV code or an external .inc it points at. texture {} expected", default="") #Only DUMMIES below for now: Tex.pov_replacement_text = StringProperty( name="Declared name:", description= "Type the declared name in custom POV code or an external .inc it points at. pigment {} expected", default="") Obj.pov_replacement_text = StringProperty( name="Declared name:", description= "Type the declared name in custom POV code or an external .inc it points at. Any POV shape expected e.g: isosurface {}", default="") Cam.pov_replacement_text = StringProperty( name="Texts in blend file", description= "Type the declared name in custom POV code or an external .inc it points at. camera {} expected", default="") ##############################TEXTURE###################################### #Custom texture gamma Tex.pov_tex_gamma_enable = BoolProperty( name="Enable custom texture gamma", description= "Notify some custom gamma for which texture has been precorrected without the file format carrying it and only if it differs from your OS expected standard (see pov doc)", default=False) Tex.pov_tex_gamma_value = FloatProperty( name="Custom texture gamma", description= "value for which the file was issued e.g. a Raw photo is gamma 1.0", min=0.45, max=5.00, soft_min=1.00, soft_max=2.50, default=1.00) #################################OBJECT#################################### #Importance sampling Obj.pov_importance_value = FloatProperty( name="Radiosity Importance", description= "Priority value relative to other objects for sampling radiosity rays. Increase to get more radiosity rays at comparatively small yet bright objects", min=0.01, max=1.00, default=1.00) #Collect photons Obj.pov_collect_photons = BoolProperty( name="Receive Photon Caustics", description= "Enable object to collect photons from other objects caustics. Turn off for objects that don't really need to receive caustics (e.g. objects that generate caustics often don't need to show any on themselves) ", default=True) ##################################CAMERA################################### #DOF Toggle Cam.pov_dof_enable = BoolProperty( name="Depth Of Field", description="Enable POV-Ray Depth Of Field ", default=True) #Aperture (Intensity of the Blur) Cam.pov_dof_aperture = FloatProperty( name="Aperture", description= "Similar to a real camera's aperture effect over focal blur (though not in physical units and independant of focal length).Increase to get more blur", min=0.01, max=1.00, default=0.25) #Aperture adaptive sampling Cam.pov_dof_samples_min = IntProperty( name="Samples Min", description="Minimum number of rays to use for each pixel", min=1, max=128, default=96) Cam.pov_dof_samples_max = IntProperty( name="Samples Max", description="Maximum number of rays to use for each pixel", min=1, max=128, default=128) Cam.pov_dof_variance = IntProperty( name="Variance", description= "Minimum threshold (fractional value) for adaptive DOF sampling (up increases quality and render time). The value for the variance should be in the range of the smallest displayable color difference", min=1, max=100000, soft_max=10000, default=256) Cam.pov_dof_confidence = FloatProperty( name="Confidence", description= "Probability to reach the real color value. Larger confidence values will lead to more samples, slower traces and better images", min=0.01, max=0.99, default=0.90) ###################################TEXT#################################### Text.pov_custom_code = BoolProperty( name="Custom Code", description="Add this text at the top of the exported POV-Ray file", default=False)
class PhobosPrefs(AddonPreferences): """The general Phobos addon settings are stored in this class. They can be edited in the User Preferences of Blender under the Addon tab. Args: Returns: """ bl_idname = __package__ logfile = StringProperty( name="logfile", subtype="FILE_PATH", default="." ) loglevel = EnumProperty( name="loglevel", items=tuple(((l,) * 3 for l in LOGLEVELS)), default="ERROR" ) logtofile = BoolProperty( name="logtofile", default=False ) logtoterminal = BoolProperty( name="logtoterminal", default=True ) modelsfolder = StringProperty( name="modelsfolder", subtype="DIR_PATH", default='' ) configfolder = StringProperty( name="configfolder", subtype="DIR_PATH", description="Path to the system-dependent config folder of Phobos.", default='' ) exportpluginsfolder = StringProperty( name='exportpluginsfolder', subtype='DIR_PATH', default='.' ) models_poses = CollectionProperty(type=ModelPoseProp) def draw(self, context): layout = self.layout layout.label(text="Log Settings") layout.prop(self, "logfile", text="log file path") layout.prop(self, "logtofile", text="write to logfile") layout.prop(self, "logtoterminal", text="write to terminal") layout.prop(self, "loglevel", text="log level") layout.separator() layout.label(text="Folders") layout.prop(self, "modelsfolder", text="models folder") layout.prop(self, "configfolder", text="config folder")
class SvVectorMathNodeMK3(bpy.types.Node, SverchCustomTreeNode): '''Vector: Add, Dot P..''' bl_idname = 'SvVectorMathNodeMK3' bl_label = 'Vector Math' bl_icon = 'THREE_DOTS' sv_icon = 'SV_VECTOR_MATH' @throttled def mode_change(self, context): self.update_sockets() current_op: EnumProperty(items=vector_math_ops, name="Function", description="Function choice", default="COMPONENT-WISE", update=mode_change) amount: FloatProperty(default=1.0, name='amount', update=updateNode) v3_input_0: FloatVectorProperty(size=3, default=(0, 0, 0), name='input a', update=updateNode) v3_input_1: FloatVectorProperty(size=3, default=(0, 0, 0), name='input b', update=updateNode) implementation_modes = [("NumPy", "NumPy", "NumPy", 0), ("MathUtils", "MathUtils", "MathUtils", 1)] implementation: EnumProperty(name='Implementation', items=implementation_modes, description='Choose calculation method', default="NumPy", update=updateNode) implementation_func_dict = { "NumPy": (numpy_vector_func_dict, recurse_fx_numpy, recurse_fxy_numpy), "MathUtils": (mathutils_vector_func_dict, recurse_fx, recurse_fxy) } output_numpy: BoolProperty(name='Output NumPy', description='Output NumPy arrays', default=False, update=updateNode) def draw_label(self): text = self.current_op.replace("_", " ") if text in {'SCALAR', '1/SCALAR'}: text = f'A * {text}' return text def draw_buttons(self, ctx, layout): layout.prop(self, "current_op", text="", icon_value=custom_icon("SV_FUNCTION")) def draw_buttons_ext(self, ctx, layout): layout.prop(self, "current_op", text="", icon_value=custom_icon("SV_FUNCTION")) layout.label(text="Implementation:") layout.prop(self, "implementation", expand=True) if self.implementation == "NumPy": layout.prop(self, "output_numpy", toggle=False) def rclick_menu(self, context, layout): layout.prop_menu_enum(self, "current_op", text="Function") layout.prop_menu_enum(self, "implementation", text="Implementation") if self.implementation == "NumPy": layout.prop(self, "output_numpy", toggle=True) def sv_init(self, context): self.inputs.new('SvVerticesSocket', "A").prop_name = 'v3_input_0' self.inputs.new('SvVerticesSocket', "B").prop_name = 'v3_input_1' self.outputs.new('SvVerticesSocket', "Out") socket_info: StringProperty(default="vv v") def update_sockets(self): socket_info = numpy_vector_func_dict.get(self.current_op)[2] if socket_info != self.socket_info: self.socket_info = socket_info t_inputs, t_outputs = socket_info.split(' ') self.outputs[0].replace_socket(socket_type.get(t_outputs)) if len(t_inputs) > len(self.inputs): self.inputs.new('SvVerticesSocket', "dummy") elif len(t_inputs) < len(self.inputs): self.inputs.remove(self.inputs[-1]) renames = 'AB' for idx, t_in in enumerate(t_inputs): s = self.inputs[idx].replace_socket(socket_type.get(t_in), renames[idx]) s.prop_name = f'v3_input_{idx}' if t_in == 'v' else 'amount' def process(self): self.ensure_enums_have_no_space(enums=["current_op"]) inputs, outputs = self.inputs, self.outputs if not outputs[0].is_linked: return func = self.implementation_func_dict[self.implementation][0].get( self.current_op)[1] num_inputs = len(inputs) # get either input data, or socket default input_one = inputs[0].sv_get(deepcopy=False) level = levels_of_list_or_np(input_one) - 1 if num_inputs == 1: recurse_func = self.implementation_func_dict[ self.implementation][1] params = [input_one, func, level] # result = recurse_func(input_one, func, level, self.output_numpy) else: input_two = inputs[1].sv_get(deepcopy=False) level = max(level, levels_of_list_or_np(input_two) - 1) min_l2_level = 3 if inputs[1].bl_idname == "SvVerticesSocket" else 2 params = [input_one, input_two, func, level, min_l2_level] recurse_func = self.implementation_func_dict[ self.implementation][2] if self.implementation == 'NumPy': params.append(self.output_numpy) result = recurse_func(*params) outputs[0].sv_set(result)
class PREFERENCES_OT_addon_install(Operator): """Install an add-on""" bl_idname = "preferences.addon_install" bl_label = "Install Add-on" overwrite: BoolProperty( name="Overwrite", description="Remove existing add-ons with the same ID", default=True, ) target: EnumProperty( name="Target Path", items=( ('DEFAULT', "Default", ""), ('PREFS', "User Prefs", ""), ), ) filepath: StringProperty( subtype='FILE_PATH', ) filter_folder: BoolProperty( name="Filter folders", default=True, options={'HIDDEN'}, ) filter_python: BoolProperty( name="Filter python", default=True, options={'HIDDEN'}, ) filter_glob: StringProperty( default="*.py;*.zip", options={'HIDDEN'}, ) def execute(self, context): import addon_utils import traceback import zipfile import shutil import os pyfile = self.filepath if self.target == 'DEFAULT': # don't use bpy.utils.script_paths("addons") because we may not be able to write to it. path_addons = bpy.utils.user_resource('SCRIPTS', "addons", create=True) else: path_addons = context.preferences.filepaths.script_directory if path_addons: path_addons = os.path.join(path_addons, "addons") if not path_addons: self.report({'ERROR'}, "Failed to get add-ons path") return {'CANCELLED'} if not os.path.isdir(path_addons): try: os.makedirs(path_addons, exist_ok=True) except: traceback.print_exc() # Check if we are installing from a target path, # doing so causes 2+ addons of same name or when the same from/to # location is used, removal of the file! addon_path = "" pyfile_dir = os.path.dirname(pyfile) for addon_path in addon_utils.paths(): if os.path.samefile(pyfile_dir, addon_path): self.report({'ERROR'}, "Source file is in the add-on search path: %r" % addon_path) return {'CANCELLED'} del addon_path del pyfile_dir # done checking for exceptional case addons_old = {mod.__name__ for mod in addon_utils.modules()} # check to see if the file is in compressed format (.zip) if zipfile.is_zipfile(pyfile): try: file_to_extract = zipfile.ZipFile(pyfile, 'r') except: traceback.print_exc() return {'CANCELLED'} if self.overwrite: for f in file_to_extract.namelist(): module_filesystem_remove(path_addons, f) else: for f in file_to_extract.namelist(): path_dest = os.path.join(path_addons, os.path.basename(f)) if os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} try: # extract the file to "addons" file_to_extract.extractall(path_addons) except: traceback.print_exc() return {'CANCELLED'} else: path_dest = os.path.join(path_addons, os.path.basename(pyfile)) if self.overwrite: module_filesystem_remove(path_addons, os.path.basename(pyfile)) elif os.path.exists(path_dest): self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} # if not compressed file just copy into the addon path try: shutil.copyfile(pyfile, path_dest) except: traceback.print_exc() return {'CANCELLED'} addons_new = {mod.__name__ for mod in addon_utils.modules()} - addons_old addons_new.discard("modules") # disable any addons we may have enabled previously and removed. # this is unlikely but do just in case. bug [#23978] for new_addon in addons_new: addon_utils.disable(new_addon, default_set=True) # possible the zip contains multiple addons, we could disallow this # but for now just use the first for mod in addon_utils.modules(refresh=False): if mod.__name__ in addons_new: info = addon_utils.module_bl_info(mod) # show the newly installed addon. context.preferences.view.show_addons_enabled_only = False context.window_manager.addon_filter = 'All' context.window_manager.addon_search = info["name"] break # in case a new module path was created to install this addon. bpy.utils.refresh_script_paths() # print message msg = ( tip_("Modules Installed (%s) from %r into %r") % (", ".join(sorted(addons_new)), pyfile, path_addons) ) print(msg) self.report({'INFO'}, msg) return {'FINISHED'} def invoke(self, context, _event): wm = context.window_manager wm.fileselect_add(self) return {'RUNNING_MODAL'}
class SvScriptNodeLite(bpy.types.Node, SverchCustomTreeNode, SvAnimatableNode): ''' snl SN Lite /// a lite version of SN ''' bl_idname = 'SvScriptNodeLite' bl_label = 'Scripted Node Lite' bl_icon = 'SCRIPTPLUGINS' def custom_enum_func(self, context): ND = self.node_dict.get(hash(self)) if ND: enum_list = ND['sockets']['custom_enum'] if enum_list: return [(ce, ce, '', idx) for idx, ce in enumerate(enum_list)] return [("A", "A", '', 0), ("B", "B", '', 1)] def custom_enum_func_2(self, context): ND = self.node_dict.get(hash(self)) if ND: enum_list = ND['sockets']['custom_enum_2'] if enum_list: return [(ce, ce, '', idx) for idx, ce in enumerate(enum_list)] return [("A", "A", '', 0), ("B", "B", '', 1)] def custom_callback(self, context, operator): ND = self.node_dict.get(hash(self)) if ND: ND['sockets']['callbacks'][operator.cb_name](self, context) def make_operator(self, new_func_name, force=False): ND = self.node_dict.get(hash(self)) if ND: callbacks = ND['sockets']['callbacks'] if not (new_func_name in callbacks) or force: # here node refers to an ast node (a syntax tree node), not a node tree node ast_node = self.get_node_from_function_name(new_func_name) slice_begin, slice_end = ast_node.body[ 0].lineno - 1, ast_node.body[-1].lineno code = '\n'.join( self.script_str.split('\n')[slice_begin - 1:slice_end + 1]) exec(code, locals(), locals()) callbacks[new_func_name] = locals()[new_func_name] script_name: StringProperty() script_str: StringProperty() node_dict = {} halt_updates: BoolProperty(name="snlite halting token") def updateNode2(self, context): if not self.halt_updates: updateNode(self, context) int_list: IntVectorProperty(name='int_list', description="Integer list", default=defaults, size=32, update=updateNode2) float_list: FloatVectorProperty(name='float_list', description="Float list", default=defaults, size=32, update=updateNode2) mode_options = [ ("To_TextBlok", "To TextBlok", "", 0), ("To_Node", "To Node", "", 1), ] selected_mode: bpy.props.EnumProperty( items=mode_options, description= "load the template directly to the node or add to textblocks", default="To_Node", update=updateNode) inject_params: BoolProperty() injected_state: BoolProperty(default=False) user_filename: StringProperty(update=updateNode) n_id: StringProperty(default='') custom_enum: bpy.props.EnumProperty(items=custom_enum_func, description="custom enum", update=updateNode) custom_enum_2: bpy.props.EnumProperty(items=custom_enum_func_2, description="custom enum 2", update=updateNode) snlite_raise_exception: BoolProperty(name="raise exception") def draw_label(self): if self.script_name: return 'SN: ' + self.script_name else: return self.bl_label def add_or_update_sockets(self, k, v): ''' 'sockets' are either 'self.inputs' or 'self.outputs' ''' sockets = getattr(self, k) for idx, (socket_description) in enumerate(v): if socket_description is UNPARSABLE: print(socket_description, idx, 'was unparsable') return if len(sockets) > 0 and idx in set(range(len(sockets))): if not are_matched(sockets[idx], socket_description): sockets[idx].replace_socket(*socket_description[:2]) else: sockets.new(*socket_description[:2]) return True def add_props_to_sockets(self, socket_info): self.id_data.freeze(hard=True) try: self.halt_updates = True for idx, (socket_description) in enumerate(socket_info['inputs']): dval = socket_description[2] print(idx, socket_description) s = self.inputs[idx] if isinstance(dval, float): s.prop_type = "float_list" s.prop_index = idx self.float_list[idx] = self.float_list[ idx] or dval # pick up current if not zero elif isinstance(dval, int): s.prop_type = "int_list" s.prop_index = idx self.int_list[idx] = self.int_list[idx] or dval except: print('some failure in the add_props_to_sockets function. ouch.') self.halt_updates = False self.id_data.unfreeze(hard=True) def flush_excess_sockets(self, k, v): sockets = getattr(self, k) if len(sockets) > len(v): num_to_remove = (len(sockets) - len(v)) for _ in range(num_to_remove): sockets.remove(sockets[-1]) def update_sockets(self): socket_info = parse_sockets(self) if not socket_info['inputs']: return for k, v in socket_info.items(): if not (k in {'inputs', 'outputs'}): continue if not self.add_or_update_sockets(k, v): print('failed to load sockets for ', k) return self.flush_excess_sockets(k, v) self.add_props_to_sockets(socket_info) self.node_dict[hash(self)] = {} self.node_dict[hash(self)]['sockets'] = socket_info return True def sv_init(self, context): self.use_custom_color = False def load(self): if not self.script_name: return text = self.get_bpy_data_from_name(self.script_name, bpy.data.texts) if text: self.script_str = text.as_string() else: print( f'bpy.data.texts not read yet, self.script_name="{self.script_name}"' ) if self.script_str: print('but script loaded locally anyway.') if self.update_sockets(): self.injected_state = False self.process() def nuke_me(self): self.script_str = '' self.script_name = '' self.node_dict[hash(self)] = {} for socket_set in [self.inputs, self.outputs]: socket_set.clear() def sv_copy(self, node): self.node_dict[hash(self)] = {} self.load() self.n_id = "" def process(self): if not all([self.script_name, self.script_str]): return self.process_script() def make_new_locals(self): # make .blend reload event work, without this the self.node_dict is empty. if not self.node_dict: # self.load() self.injected_state = False self.update_sockets() # make inputs local, do function with inputs, return outputs if present ND = self.node_dict.get(hash(self)) if not ND: print('hash invalidated') self.injected_state = False self.update_sockets() ND = self.node_dict.get(hash(self)) self.load() socket_info = ND['sockets'] local_dict = {} for idx, s in enumerate(self.inputs): sock_desc = socket_info['inputs'][idx] if s.is_linked: val = s.sv_get(default=[[]]) if sock_desc[3]: val = {0: val, 1: val[0], 2: val[0][0]}.get(sock_desc[3]) else: val = sock_desc[2] if isinstance(val, (int, float)): # extra pussyfooting for the load sequence. t = s.sv_get() if t and t[0] and len(t[0]) > 0: val = t[0][0] local_dict[s.name] = val return local_dict def get_node_from_function_name(self, func_name): """ this seems to get enough info for a snlite stateful setup function. """ tree = ast.parse(self.script_str) for node in tree.body: if isinstance(node, ast.FunctionDef) and node.name == func_name: return node def get_setup_code(self): ast_node = self.get_node_from_function_name('setup') if ast_node: begin_setup = ast_node.body[0].lineno - 1 end_setup = ast_node.body[-1].lineno code = '\n'.join( self.script_str.split('\n')[begin_setup:end_setup]) return 'def setup():\n\n' + code + '\n return locals()\n' def get_ui_code(self): ast_node = self.get_node_from_function_name('ui') if ast_node: begin_setup = ast_node.body[0].lineno - 1 end_setup = ast_node.body[-1].lineno code = '\n'.join( self.script_str.split('\n')[begin_setup:end_setup]) return 'def ui(self, context, layout):\n\n' + code + '\n\n' def inject_state(self, local_variables): setup_result = self.get_setup_code() if setup_result: exec(setup_result, local_variables, local_variables) setup_locals = local_variables.get('setup')() local_variables.update(setup_locals) local_variables['socket_info']['setup_state'] = setup_locals self.injected_state = True def inject_draw_buttons(self, local_variables): draw_ui_result = self.get_ui_code() if draw_ui_result: exec(draw_ui_result, local_variables, local_variables) ui_func = local_variables.get('ui') local_variables['socket_info']['drawfunc'] = ui_func def process_script(self): __local__dict__ = self.make_new_locals() locals().update(__local__dict__) locals().update({ 'vectorize': vectorize, 'bpy': bpy, 'np': np, 'ddir': ddir, 'bmesh_from_pydata': bmesh_from_pydata, 'pydata_from_bmesh': pydata_from_bmesh }) for output in self.outputs: locals().update({output.name: []}) try: socket_info = self.node_dict[hash(self)]['sockets'] # inject once! if not self.injected_state: self.inject_state(locals()) self.inject_draw_buttons(locals()) else: locals().update(socket_info['setup_state']) if self.inject_params: locals().update({ 'parameters': [__local__dict__.get(s.name) for s in self.inputs] }) exec(self.script_str, locals(), locals()) for idx, _socket in enumerate(self.outputs): vals = locals()[_socket.name] self.outputs[idx].sv_set(vals) set_autocolor(self, True, READY_COLOR) except Exception as err: print("Unexpected error:", sys.exc_info()[0]) exc_type, exc_value, exc_traceback = sys.exc_info() lineno = traceback.extract_tb(exc_traceback)[-1][1] print('on line: ', lineno) show = traceback.print_exception show(exc_type, exc_value, exc_traceback, limit=6, file=sys.stdout) if hasattr( self, "snlite_raise_exception") and self.snlite_raise_exception: raise # SNLITE_EXCEPTION(sys.exc_info()[2]) from err def custom_draw(self, context, layout): tk = self.node_dict.get(hash(self)) if not tk or not tk.get('sockets'): return snlite_info = tk['sockets'] if snlite_info: # snlite supplied custom file handler solution fh = snlite_info.get('display_file_handler') if fh: layout.prop_search(self, 'user_filename', bpy.data, 'texts', text='filename') # user supplied custom draw function f = snlite_info.get('drawfunc') if f: f(self, context, layout) def draw_buttons(self, context, layout): sn_callback = 'node.scriptlite_ui_callback' if not self.script_str: col = layout.column(align=True) row = col.row() row.prop_search(self, 'script_name', bpy.data, 'texts', text='', icon='TEXT') row.operator(sn_callback, text='', icon='PLUGIN').fn_name = 'load' else: self.draw_animatable_buttons(layout, icon_only=True) col = layout.column(align=True) row = col.row() row.operator(sn_callback, text='Reload').fn_name = 'load' row.operator(sn_callback, text='Clear').fn_name = 'nuke_me' self.custom_draw(context, layout) def draw_buttons_ext(self, _, layout): row = layout.row() row.prop(self, 'selected_mode', expand=True) col = layout.column() col.menu(SV_MT_ScriptNodeLitePyMenu.bl_idname) box = layout.box() r = box.row() r.label(text="extra snlite features") if hasattr(self, "snlite_raise_exception"): r = box.row() r.prop(self, "snlite_raise_exception", toggle=True, text="raise errors to tree level") # ---- IO Json storage is handled in this node locally ---- def storage_set_data(self, node_ref): texts = bpy.data.texts data_list = node_ref.get('snlite_ui') if data_list: # self.node_dict[hash(self)]['sockets']['snlite_ui'] = ui_elements for data_json_str in data_list: data_dict = json.loads(data_json_str) if data_dict['bl_idname'] == 'ShaderNodeRGBCurve': set_rgb_curve(data_dict) includes = node_ref.get('includes') if includes: for include_name, include_content in includes.items(): new_text = texts.new(include_name) new_text.from_string(include_content) if include_name == new_text.name: continue print('| in', node_ref.name, 'the importer encountered') print('| an include called', include_name, '. While trying') print('| to write this file to bpy.data.texts another file') print('| with the same name was encountered. The importer') print('| automatically made a datablock called', new_text.name) def storage_get_data(self, node_dict): # this check and function call is needed to allow loading node trees directly # from a .blend in order to export them via create_dict_of_tree if not self.node_dict or not self.node_dict.get(hash(self)): self.make_new_locals() storage = self.node_dict[hash(self)]['sockets'] ui_info = storage['snlite_ui'] node_dict['snlite_ui'] = [] print(ui_info) for _, info in enumerate(ui_info): mat_name = info['mat_name'] node_name = info['node_name'] bl_idname = info['bl_idname'] if bl_idname == 'ShaderNodeRGBCurve': data = get_rgb_curve(mat_name, node_name) print(data) data_json_str = json.dumps(data) node_dict['snlite_ui'].append(data_json_str) includes = storage['includes'] if includes: node_dict['includes'] = {} for k, v in includes.items(): node_dict['includes'][k] = v
class PREFERENCES_OT_studiolight_install(Operator): """Install a user defined studio light""" bl_idname = "preferences.studiolight_install" bl_label = "Install Custom Studio Light" files: CollectionProperty( name="File Path", type=OperatorFileListElement, ) directory: StringProperty( subtype='DIR_PATH', ) filter_folder: BoolProperty( name="Filter folders", default=True, options={'HIDDEN'}, ) filter_glob: StringProperty( default="*.png;*.jpg;*.hdr;*.exr", options={'HIDDEN'}, ) type: EnumProperty( items=( ('MATCAP', "MatCap", ""), ('WORLD', "World", ""), ('STUDIO', "Studio", ""), ) ) def execute(self, context): import os import shutil prefs = context.preferences path_studiolights = os.path.join("studiolights", self.type.lower()) path_studiolights = bpy.utils.user_resource('DATAFILES', path_studiolights, create=True) if not path_studiolights: self.report({'ERROR'}, "Failed to create Studio Light path") return {'CANCELLED'} for e in self.files: shutil.copy(os.path.join(self.directory, e.name), path_studiolights) prefs.studio_lights.load(os.path.join(path_studiolights, e.name), self.type) # print message msg = ( tip_("StudioLight Installed %r into %r") % (", ".join(e.name for e in self.files), path_studiolights) ) print(msg) self.report({'INFO'}, msg) return {'FINISHED'} def invoke(self, context, _event): wm = context.window_manager if self.type == 'STUDIO': self.filter_glob = "*.sl" wm.fileselect_add(self) return {'RUNNING_MODAL'}
class AddTextToStorageVars(PropertyGroup): tags: StringProperty(name='Tags (comma separated)', description='Add some tags to describe this text', default='')