Example #1
0
class GGT_OT_JOIN_ANIMATIONS_OT_GGT(Operator, ImportHelper):
    bl_idname = "wm_ggt.join_animations"
    bl_label = "Join Animations"
    bl_description = "Join mixamo animations into a single armature"
    bl_options = {'PRESET', 'UNDO'}
    filename_ext = ".fbx"
    filter_glob: StringProperty(default="*.fbx", options={'HIDDEN'})
    files: CollectionProperty(type=bpy.types.PropertyGroup)

    def getSelectedFiles(self, file_path, files):
        # If a folder was selected, import all animations of that folder, otherwise only import the selected models
        selected_file_or_path = self.properties.filepath
        if os.path.isdir(selected_file_or_path):
            files = [
                os.path.join(selected_file_or_path, file)
                for file in os.listdir(selected_file_or_path)
            ]
        else:
            path = os.path.dirname(selected_file_or_path)
            files = [
                os.path.join(path, file.name) for file in self.properties.files
            ]

        for file in files:
            if not os.path.exists(file):
                self.report(
                    {'ERROR'},
                    'Animation file {} does not exist, skipped import.'.format(
                        file))
                files.remove(file)
        return files

    def importModels(self, file_names, target_armature, context):
        scene = context.scene
        tool = scene.godot_game_tools
        extensions = ['fbx']
        armature_key = "main_armature"
        valid_files = []
        file_names_list = []
        removeList = []
        # Debug
        removeImports = True
        imported_objs = []

        if tool.target_object is not None:
            for filename in file_names:
                for ext in extensions:
                    if filename.lower().endswith('.{}'.format(ext)):
                        valid_files.append(filename)
                        break

            for file_path in valid_files:
                bpy.ops.object.select_all(action='DESELECT')
                if ext == "fbx":
                    name = os.path.basename(file_path)
                    if hasattr(bpy.types, bpy.ops.import_scene.fbx.idname()):
                        actionName, actionExtension = os.path.splitext(name)
                        if actionName != "T-Pose":
                            # Local Variable
                            file_names_list.append(actionName)
                            bpy.ops.import_scene.fbx(filepath=file_path)
                            imported_objs.append(
                                bpy.context.view_layer.objects.active)

            if len(file_names_list) > 0:
                index = 0
                for obj in imported_objs:
                    obj.animation_data.action.name = file_names_list[index]
                    # Rename the bones
                    for bone in obj.pose.bones:
                        if ':' not in bone.name: continue
                        bone.name = bone.name.split(":")[1]
                    removeList.append(obj)
                    meshes = [obj for obj in obj.children]
                    for mesh in meshes:
                        removeList.append(mesh)
                    index += 1

            # Remove Cleared Keyframe Actions - Mixamo Fix
            if len(file_names_list) > 0:
                rename_index = 0
                for action in bpy.data.actions:
                    if len(action.fcurves) == 0:
                        bpy.data.actions.remove(action)
                    else:
                        if action.name not in file_names_list and action.get(
                                armature_key) is None:
                            if file_names_list[rename_index]:
                                action[armature_key] = armature_key
                                bpy.data.actions[
                                    action.
                                    name].name = file_names_list[rename_index]
                                rename_index += 1

        # Delete Imported Armatures
        if removeImports:
            objs = [ob for ob in removeList if ob.type in ('ARMATURE', 'MESH')]
            bpy.ops.object.delete({"selected_objects": objs})
            bpy.context.view_layer.objects.active = target_armature

    def setDefaultAnimation(self, context):
        scene = context.scene
        tool = scene.godot_game_tools
        target_armature = tool.target_object
        if target_armature: target_armature["animation_tree_preset"] = None
        if len(bpy.data.actions) > 0:
            for action in bpy.data.actions:
                animation = action.name
                if animation in "T-Pose":
                    tool.animations = animation

    def execute(self, context):
        scene = context.scene
        tool = scene.godot_game_tools
        target_armature = tool.target_object
        files = self.getSelectedFiles(self.properties.filepath,
                                      self.properties.files)
        self.importModels(sorted(files), target_armature, context)
        bpy.ops.scene.process_actions('EXEC_DEFAULT')
        self.setDefaultAnimation(context)
        self.report({'INFO'}, 'Animations Imported Successfully')
        return {'FINISHED'}
Example #2
0
class SvIterationNode(bpy.types.Node, SverchCustomTreeNode, StoreSockets):
    bl_idname = 'SvIterationNode'
    bl_label = 'Group Inputs'
    bl_icon = 'OUTLINER_OB_EMPTY'

    iter_count = IntProperty(name="Count")
    group_name = StringProperty()

    def update(self):
        '''
        Override inherited
        '''
        pass

    def draw_buttons(self, context, layout):
        if self.id_data.bl_idname == "SverchCustomTreeType":
            op = layout.operator("node.sv_node_group_edit")
            op.group_name = self.group_name
            layout.prop(self, "iter_count")

    def adjust_sockets(self, nodes):
        swap = {"inputs": "outputs", "outputs": "inputs"}
        for n in nodes:
            data = ast.literal_eval(n.socket_data)
            for k, values in data.items():
                sockets = getattr(self, swap[k])
                for i, s in enumerate(values):
                    if i < len(sockets):
                        sockets[i].name = s[1]
                    else:
                        sockets.new(*s)

    def process(self):
        group_ng = bpy.data.node_groups[self.group_name]
        in_node = find_node("SvGroupInputsNode", group_ng)
        out_node = find_node('SvGroupOutputsNode', group_ng)
        ul = make_tree_from_nodes([out_node.name], group_ng, down=False)

        for socket in self.inputs:
            if socket.is_linked:
                data = socket.sv_get(deepcopy=False)
                in_node.outputs[socket.name].sv_set(data)
        #  get update list
        #  could be cached
        for i in range(self.iter_count):
            do_update(ul, group_ng.nodes)
            for socket in out_node.inputs:
                if socket.is_linked:
                    data = out_node.inputs[socket.name].sv_get(deepcopy=False)
                    socket.sv_set(data)
                    in_node.outputs[socket.name].sv_set(data)

        # set output sockets correctly
        for socket in self.outputs:
            if socket.is_linked:
                data = out_node.inputs[socket.name].sv_get(deepcopy=False)
                socket.sv_set(data)

    def get_sockets(self):
        yield self.inputs, "inputs"
        yield self.outputs, "outputs"
Example #3
0
class LuxCoreConfig(PropertyGroup):
    """
    Main config storage class.
    Access (in ui or export) with scene.luxcore.config
    """

    # These settings are mostly not directly transferrable to LuxCore properties
    # They need some if/else decisions and aggregation, e.g. to build the engine name from parts
    engines = [
        ("PATH", "Path", "Unidirectional path tracer; " + SIMPLE_DESC, 0),
        ("BIDIR", "Bidir", "Bidirectional path tracer; " + COMPLEX_DESC, 1),
    ]
    engine: EnumProperty(name="Engine", items=engines, default="PATH")

    # Only available when tiled rendering is off
    samplers = [
        ("SOBOL", "Sobol", SIMPLE_DESC, 0),
        ("METROPOLIS", "Metropolis", COMPLEX_DESC, 1),
        ("RANDOM", "Random",
         "Recommended only if the BCD denoiser is used (use Sobol otherwise)",
         2),
    ]
    sampler: EnumProperty(name="Sampler", items=samplers, default="SOBOL")

    # SOBOL properties
    sobol_adaptive_strength: FloatProperty(
        name="Adaptive Strength",
        default=0.9,
        min=0,
        max=0.95,
        description=SOBOL_ADAPTIVE_STRENGTH_DESC)

    # Noise estimation (used by adaptive samplers like SOBOL and RANDOM)
    noise_estimation: PointerProperty(type=LuxCoreConfigNoiseEstimation)

    # METROPOLIS properties
    # sampler.metropolis.largesteprate
    metropolis_largesteprate: FloatProperty(name="Large Mutation Probability",
                                            default=40,
                                            min=0,
                                            max=100,
                                            precision=0,
                                            subtype="PERCENTAGE",
                                            description=LARGE_STEP_RATE_DESC)
    # sampler.metropolis.maxconsecutivereject
    metropolis_maxconsecutivereject: IntProperty(
        name="Max Consecutive Rejects",
        default=512,
        min=0,
        description=MAX_CONSECUTIVE_REJECT_DESC)
    # sampler.metropolis.imagemutationrate
    metropolis_imagemutationrate: FloatProperty(
        name="Image Mutation Rate",
        default=10,
        min=0,
        max=100,
        precision=0,
        subtype="PERCENTAGE",
        description=IMAGE_MUTATION_RATE_DESC)

    # Only available when engine is PATH (not BIDIR)
    devices = [
        ("CPU", "CPU",
         "Use the arithmetic logic units in your central processing unit", 0),
        ("OCL", "OpenCL", "Use the good ol' pixel cruncher", 1),
    ]
    device: EnumProperty(name="Device", items=devices, default="CPU")
    # A trick so we can show the user that bidir can only be used on the CPU (see UI code)
    bidir_device: EnumProperty(name="Device",
                               items=devices,
                               default="CPU",
                               description="Bidir only available on CPU")

    use_tiles: BoolProperty(name="Tiled",
                            default=False,
                            description=TILED_DESCRIPTION)

    # Special properties of the various engines
    path: PointerProperty(type=LuxCoreConfigPath)
    tile: PointerProperty(type=LuxCoreConfigTile)
    # BIDIR properties
    # light.maxdepth
    # TODO description
    bidir_light_maxdepth: IntProperty(name="Light Depth",
                                      default=10,
                                      min=1,
                                      soft_max=16)
    # path.maxdepth
    # TODO description
    bidir_path_maxdepth: IntProperty(name="Eye Depth",
                                     default=10,
                                     min=1,
                                     soft_max=16)

    # Pixel filter
    filters = [
        ("BLACKMANHARRIS", "Blackman-Harris",
         "Default, usually the best option", 0),
        ("MITCHELL_SS", "Mitchell",
         "Sharp, but can produce black ringing artifacts around bright pixels",
         1), ("GAUSSIAN", "Gaussian", "Blurry", 2),
        ("NONE", "None",
         "Disable pixel filtering. Fastest setting when rendering on GPU", 3)
    ]
    filter: EnumProperty(name="Filter",
                         items=filters,
                         default="BLACKMANHARRIS",
                         description=FILTER_DESC)
    filter_width: FloatProperty(name="Filter Width",
                                default=1.5,
                                min=0.5,
                                soft_max=3,
                                description=FILTER_WIDTH_DESC,
                                subtype="PIXEL")
    gaussian_alpha: FloatProperty(
        name="Gaussian Filter Alpha",
        default=2,
        min=0.1,
        max=10,
        description=
        "Gaussian rate of falloff. Lower values give blurrier images")

    # Light strategy
    light_strategy_items = [
        ("LOG_POWER", "Log Power", LOG_POWER_DESC, 0),
        ("POWER", "Power", POWER_DESC, 1),
        ("UNIFORM", "Uniform", UNIFORM_DESC, 2),
    ]
    light_strategy: EnumProperty(
        name="Light Strategy",
        items=light_strategy_items,
        default="LOG_POWER",
        description="Decides how the lights in the scene are sampled")

    # Special properties of the direct light sampling cache
    dls_cache: PointerProperty(type=LuxCoreConfigDLSCache)
    # Special properties of the photon GI cache
    photongi: PointerProperty(type=LuxCoreConfigPhotonGI)
    # Special properties of the env. light cache (aka automatic portals)
    envlight_cache: PointerProperty(type=LuxCoreConfigEnvLightCache)

    # FILESAVER options
    use_filesaver: BoolProperty(name="Only write LuxCore scene", default=False)
    filesaver_format_items = [
        ("TXT", "Text", "Save as .scn and .cfg text files", 0),
        ("BIN", "Binary", "Save as .bcf binary file", 1),
    ]
    filesaver_format: EnumProperty(name="",
                                   items=filesaver_format_items,
                                   default="TXT")
    filesaver_path: StringProperty(
        name="",
        subtype="DIR_PATH",
        description="Output path where the scene is saved")

    # Seed
    seed: IntProperty(name="Seed", default=1, min=1, description=SEED_DESC)
    use_animated_seed: BoolProperty(name="Animated Seed",
                                    default=False,
                                    description=ANIM_SEED_DESC)

    # Min. epsilon settings (drawn in ui/units.py)
    show_min_epsilon: BoolProperty(
        name="Advanced LuxCore Settings",
        default=False,
        description="Show/Hide advanced LuxCore features. "
        "Only change them if you know what you are doing")
    min_epsilon: FloatProperty(
        name="Min. Epsilon",
        default=1e-5,
        soft_min=1e-6,
        soft_max=1e-1,
        precision=5,
        description=
        "User higher values when artifacts due to floating point precision "
        "issues appear in the rendered image")
    max_epsilon: FloatProperty(
        name="Max. Epsilon",
        default=1e-1,
        soft_min=1e-3,
        soft_max=1e+2,
        precision=5,
        description="Might need adjustment along with the min epsilon to avoid "
        "artifacts due to floating point precision issues")

    film_opencl_enable: BoolProperty(
        name="Use OpenCL",
        default=True,
        description=
        "Use OpenCL to accelerate tonemapping and other imagepipeline "
        "operations (applies to viewport and final render). "
        "Disabling this option will save a bit of RAM, especially if "
        "the render resolution is large. "
        "This option is ignored in Non-OpenCL builds")

    def film_opencl_device_items_callback(self, context):
        devices = context.scene.luxcore.opencl.devices
        items = [("none", "None", "", 0)]
        items += [(str(i), device.name, "", i + 1)
                  for i, device in enumerate(devices)
                  if device.type == "OPENCL_GPU"]
        # There is a known bug with using a callback,
        # Python must keep a reference to the strings
        # returned or Blender will misbehave or even crash.
        global film_opencl_device_items
        film_opencl_device_items = items
        return items

    film_opencl_device: EnumProperty(
        name="Device",
        items=film_opencl_device_items_callback,
        description="Which device to use to compute the imagepipeline")
Example #4
0
class RDSegment(bpy.types.PropertyGroup):
    """
    Bone property, contains all relevant bone information for RobotDesigner
    """
    def callbackSegments(self, context):
        segment_name = context.active_bone.name
        # We should not have to recurse when updating a local property.
        UpdateSegments.run(segment_name=segment_name, recurse=False)

    def getTransform(self):
        """
        returned transform matrix is of the form translation*parentMatrix*rotation
        parent is dependent of parent mode, that is either Euler or DH
        either translation or rotation is I_4 dependent of the joint type,
        whereas a revolute joints contributes a rotation only and a
        prismatic joint contributes a translation only
        """

        translation = Matrix()  # initialize as I_4 matrix
        rotation = Matrix()  # initialize as I_4 matrix
        axis_matrix = (
            Matrix()
        )  # contains axis information which should be applied to parentMatrix

        if self.axis_revert:
            inverted = -1
        else:
            inverted = 1

        if self.parentMode == "EULER":
            parentMatrix = self.Euler.getTransformFromParent()
        else:  # self.parentMode == 'DH'
            parentMatrix = self.DH.getTransformFromParent()

        if self.jointMode == "REVOLUTE":
            if self.axis == "X":
                rotation = Euler(
                    (radians(self.theta.value + self.theta.offset), 0, 0),
                    "XYZ").to_matrix()
                rotation.resize_4x4()
                axis_matrix = Euler((radians(180 * (1 - inverted) / 2), 0, 0),
                                    "XYZ").to_matrix()
                axis_matrix.resize_4x4()
            elif self.axis == "Y":
                rotation = Euler(
                    (0, radians(self.theta.value + self.theta.offset), 0),
                    "XYZ").to_matrix()
                rotation.resize_4x4()
                axis_matrix = Euler((0, radians(180 * (1 - inverted) / 2), 0),
                                    "XYZ").to_matrix()
                axis_matrix.resize_4x4()
            elif self.axis == "Z":
                rotation = Euler(
                    (0, 0, radians(self.theta.value + self.theta.offset)),
                    "XYZ").to_matrix()
                rotation.resize_4x4()
                axis_matrix = Euler((0, 0, radians(180 * (1 - inverted) / 2)),
                                    "XYZ").to_matrix()
                axis_matrix.resize_4x4()

        if self.jointMode == "PRISMATIC":
            if self.axis == "X":
                translation = Matrix.Translation(
                    (inverted * (self.d.value + self.d.offset), 0, 0, 1))
            elif self.axis == "Y":
                translation = Matrix.Translation(
                    (0, inverted * (self.d.value + self.d.offset), 0, 1))
            elif self.axis == "Z":
                translation = Matrix.Translation(
                    (0, 0, inverted * (self.d.value + self.d.offset), 1))

        if (self.jointMode == "FIXED" or self.jointMode == "REVOLUTE2"
                or self.jointMode == "UNIVERSAL" or self.jointMode == "BALL"
            ):  # todo: check if this is right for fixed joint type
            translation = Matrix.Translation((0, 0, 0, 1))

        return parentMatrix @ axis_matrix, translation @ rotation
        # return parentMatrix, translation*rotation

    jointMode: EnumProperty(
        items=[
            ("REVOLUTE", "Revolute", "revolute joint"),
            ("PRISMATIC", "Prismatic", "prismatic joint"),
            ("REVOLUTE2", "Revolute2", "revolute2 joint"),
            ("UNIVERSAL", "Universal", "universal joint"),
            ("BALL", "Ball", "ball joint"),
            ("FIXED", "Fixed", "fixed joint"),
        ],
        name="Joint Mode",
        update=callbackSegments,
    )

    parentMode: EnumProperty(
        items=[("EULER", "Euler", "Euler mode"), ("DH", "DH", "DH mode")],
        name="Parent Mode",
        update=callbackSegments,
    )

    axis: EnumProperty(
        items=[("X", "X", "X Axis"), ("Y", "Y", "Y Axis"),
               ("Z", "Z", "Z Axis")],
        name="Active Axis",
        default="Z",
        update=callbackSegments,
    )

    RD_Bone: BoolProperty(name="Created by RD", default=False)

    axis_revert: BoolProperty(name="Axis Reverted?",
                              default=False,
                              update=callbackSegments)

    dynamic_limits: PointerProperty(type=RDActuator)
    theta: PointerProperty(
        type=RDDegreeOfFreedom
    )  # Joint transform + limits, relative to local frame.
    d: PointerProperty(type=RDDegreeOfFreedom)
    jointController: PointerProperty(type=RDJointController)
    linkInfo: PointerProperty(type=RDLinkInfo)
    ode: PointerProperty(type=RDOde)
    joint_dynamics: PointerProperty(type=RDJointDynamics)
    Euler: PointerProperty(
        type=RDEulerAnglesSegment
    )  # Frame relative to parent as Euler parameter, either Euler or DH is used
    DH: PointerProperty(
        type=RDDenavitHartenbergSegment
    )  # Frame relative to parent as Denavit Hartenberg, either Euler or DH is used
    world: BoolProperty(name="Attach Link to World", default=False)
    joint_name: StringProperty(
        name="Joint Name: ")  # Name of parent joint of segment
Example #5
0
    "tracker_url": "https://github.com/physycom/inertial_to_blender/issues"
}

import bpy
import sys, math, os
from pathlib import Path
sys.path.append(str(Path(__file__).parent))
# different name from project and deployed zip
from . import addon_updater_ops
from blender import bootstrap

from bpy.props import StringProperty, BoolProperty

bpy.types.Scene.datasetPath = StringProperty(
    name="Dataset path",
    description=":",
    default="",
    maxlen=2056,
)

bpy.types.Scene.use_gps = BoolProperty(name="Use GPS Data",
                                       description="Use GPS data",
                                       default=False)

bpy.types.Scene.crash = BoolProperty(
    name="Reconstruct crash",
    description="The dataset represent a crash, reconstruct it",
    default=False)

bpy.types.Scene.ignore_z = BoolProperty(
    name="Ignore vertical motion",
    description="Ignore movement on z axis",
Example #6
0
class SvPrifilizer(bpy.types.Operator):
    """SvPrifilizer"""
    bl_idname = "node.sverchok_profilizer"
    bl_label = "SvPrifilizer"
    bl_options = {'REGISTER', 'UNDO'}

    nodename: StringProperty(name='nodename')
    treename: StringProperty(name='treename')
    knotselected: BoolProperty(
        description='if selected knots than use extended parsing in PN',
        default=False)
    x: BoolProperty(default=True)
    y: BoolProperty(default=True)

    def stringadd(self, x, selected=False):
        precision = bpy.data.node_groups[self.treename].nodes[
            self.nodename].precision
        if selected:
            if self.x: letterx = '+a'
            else: letterx = ''
            if self.y: lettery = '+a'
            else: lettery = ''
            a = '(' + str(round(
                x[0], precision)) + letterx + ')' + ',' + '(' + str(
                    round(x[1], precision)) + lettery + ')' + ' '
            self.knotselected = True
        else:
            a = str(round(x[0], precision)) + ',' + str(round(x[1],
                                                              precision)) + ' '
        return a

    def curve_points_count(self):
        count = bpy.data.node_groups[self.treename].nodes[
            self.nodename].curve_points_count
        return str(count)

    def execute(self, context):
        node = bpy.data.node_groups[self.treename].nodes[self.nodename]
        precision = node.precision
        subdivisions = node.curve_points_count
        if not bpy.context.selected_objects:
            print('Pofiler: Select curve!')
            self.report({'INFO'}, 'Select CURVE first')
            return {'CANCELLED'}
        if not bpy.context.selected_objects[0].type == 'CURVE':
            print('Pofiler: NOT a curve selected')
            self.report({'INFO'}, 'It is not a curve selected for profiler')
            return {'CANCELLED'}

        objs = bpy.context.selected_objects
        names = str([o.name for o in objs])[1:-2]

        # test for POLY or NURBS curve types, these are not yet supported
        spline_type = objs[0].data.splines[0].type
        if spline_type in {'POLY', 'NURBS'}:
            msg = 'Pofiler: does not support {0} curve type yet'.format(
                spline_type)
            print(msg)
            self.report({'INFO'}, msg)
            return {'CANCELLED'}

        # collect paths
        op = []
        clos = []
        for obj in objs:
            for spl in obj.data.splines:
                op.append(spl.bezier_points)
                clos.append(spl.use_cyclic_u)

        # define path to text
        values = '# Here is autogenerated values, \n# Please, rename text to avoid data loose.\n'
        values += '# Objects are: \n# %a' % (names) + '.\n'
        values += '# Object origin should be at 0,0,0. \n'
        values += '# Property panel has precision %a \n# and curve subdivision %s.\n\n' % (
            precision, subdivisions)
        # also future output for viewer indices
        out_points = []
        out_names = []
        ss = 0
        for ob_points, clo in zip(op, clos):
            values += '# Spline %a\n' % (ss)
            ss += 1
            # handles preperation
            curves_left = [i.handle_left_type for i in ob_points]
            curves_right = ['v'] + [i.handle_right_type
                                    for i in ob_points][:-1]
            # first collect C,L values to compile them later per point
            types = ['FREE', 'ALIGNED', 'AUTO']
            curves = [
                'C ' if x in types or c in types else 'L '
                for x, c in zip(curves_left, curves_right)
            ]
            # line for if curve was before line or not
            line = False
            curve = False

            for i, c in zip(range(len(ob_points)), curves):
                co = ob_points[i].co
                if not i:
                    # initial value
                    values += '\n'
                    values += 'M '
                    co = ob_points[0].co[:]
                    values += self.stringadd(co,
                                             ob_points[0].select_control_point)
                    values += '\n'
                    out_points.append(co)
                    out_names.append(['M.0'])
                    # pass if first 'M' that was used already upper
                    continue

                elif c == 'C ':
                    values += '\n'
                    values += '#C.' + str(i) + '\n'
                    values += c
                    hr = ob_points[i - 1].handle_right[:]
                    hl = ob_points[i].handle_left[:]
                    # hr[0]hr[1]hl[0]hl[1]co[0]co[1] 20 0
                    values += self.stringadd(
                        hr, ob_points[i - 1].select_right_handle)
                    values += self.stringadd(hl,
                                             ob_points[i].select_left_handle)
                    values += self.stringadd(co,
                                             ob_points[i].select_control_point)
                    values += self.curve_points_count()
                    values += ' 0 '
                    if curve:
                        values += '\n'
                    out_points.append(hr[:])
                    out_points.append(hl[:])
                    out_points.append(co[:])
                    #namecur = ['C.'+str(i)]
                    out_names.extend([['C.' + str(i) + 'h1'],
                                      ['C.' + str(i) + 'h2'],
                                      ['C.' + str(i) + 'k']])
                    line = False
                    curve = True

                elif c == 'L ' and not line:
                    if curve:
                        values += '\n'
                    values += '#L.' + str(i) + '...' + '\n'
                    values += c
                    values += self.stringadd(co,
                                             ob_points[i].select_control_point)
                    out_points.append(co[:])
                    out_names.append(['L.' + str(i)])
                    line = True
                    curve = False

                elif c == 'L ' and line:
                    values += self.stringadd(co,
                                             ob_points[i].select_control_point)
                    out_points.append(co[:])
                    out_names.append(['L.' + str(i)])

            if clo:
                if ob_points[0].handle_left_type in types or ob_points[
                        -1].handle_right_type in types:
                    line = False
                    values += '\n'
                    values += '#C.' + str(i + 1) + '\n'
                    values += 'C '
                    hr = ob_points[-1].handle_right[:]
                    hl = ob_points[0].handle_left[:]
                    # hr[0]hr[1]hl[0]hl[1]co[0]co[1] 20 0
                    values += self.stringadd(hr,
                                             ob_points[-1].select_right_handle)
                    values += self.stringadd(hl,
                                             ob_points[0].select_left_handle)
                    values += self.stringadd(ob_points[0].co,
                                             ob_points[0].select_control_point)
                    values += self.curve_points_count()
                    values += ' 0 '
                    values += '\n'
                    out_points.append(hr[:])
                    out_points.append(hl[:])
                    out_names.extend([['C.' + str(i + 1) + 'h1'],
                                      ['C.' + str(i + 1) + 'h2']])
                    # preserving overlapping
                    #out_points.append(ob_points[0].co[:])
                    #out_names.append(['C'])
                if not line:
                    # hacky way till be fixed x for curves not only for lines
                    values += '# hacky way till be fixed x\n# for curves not only for lines'
                    values += '\nL ' + self.stringadd(
                        ob_points[0].co, ob_points[0].select_control_point)
                    values += '\nx \n\n'
                else:
                    values += '\nx \n\n'

        if self.knotselected:
            values += '# expression (#+a) added because \n# you selected knots in curve'
        self.write_values(self.nodename, values)
        #print(values)
        node.filename = self.nodename
        #print([out_points], [out_names])
        # sharing data to node:
        node.SvLists.clear()
        node.SvSubLists.clear()
        node.SvLists.add().name = 'knots'
        for k in out_points:
            item = node.SvLists['knots'].SvSubLists.add()
            item.SvX, item.SvY, item.SvZ = k
        #lll = node.SvLists['knots'].SvSubLists[0]
        #print(lll.SvX,lll.SvY,lll.SvZ)
        node.SvLists.add().name = 'knotsnames'
        for k in out_names:
            item = node.SvLists['knotsnames'].SvSubLists.add()
            item.SvName = k[0]
            #print(k[0])
        index_viewer_adding(node)
        node.extended_parsing = self.knotselected
        viewedraw_adding(node)
        if self.knotselected:
            float_add_if_selected(node)
        #print(node.SvLists['knotsnames'].SvSubLists[0].SvName)
        return {'FINISHED'}

    def write_values(self, text, values):
        texts = bpy.data.texts.items()
        exists = False
        for t in texts:
            if bpy.data.texts[t[0]].name == text:
                exists = True
                break

        if not exists:
            bpy.data.texts.new(text)
        bpy.data.texts[text].clear()
        bpy.data.texts[text].write(values)
class SvDupliInstancesMK4(bpy.types.Node, SverchCustomTreeNode):
    bl_idname = 'SvDupliInstancesMK4'
    bl_label = 'Dupli instancer mk4'
    bl_icon = 'OUTLINER_OB_EMPTY'

    def set_child_quota(self, context):
        # was used for string child property
        updateNode(self, context)

        # post update check
        if self.auto_release:
            parent = self.name_node_generated_parent
            if parent:
                for obj in bpy.data.objects[parent].children:
                    if not obj.name == self.name_child:
                        obj.parent = None

    name_node_generated_parent = StringProperty(
        description="name of the parent that this node generates",
        update=updateNode)

    scale = BoolProperty(default=False,
        description="scale children", update=updateNode)

    auto_release = BoolProperty(update=set_child_quota)

    def sv_init(self, context):
        #self.inputs.new("SvObjectSocket", "parent")
        self.inputs.new("SvObjectSocket", "child")
        self.inputs.new("MatrixSocket", "matr/vert")
        self.name_node_generated_parent = 'parant'

    def draw_buttons(self, context, layout):
        col = layout.column(align=True)
        col.prop(self, 'name_node_generated_parent', text='', icon='LOOPSEL')
        #col.prop_search(self, 'name_child', bpy.data, 'objects', text='')
        col.prop(self, 'scale', text='Scale children', toggle=True)
        col.prop(self, 'auto_release', text='One Object only', toggle=True)

    def process(self):
        #objectsP = self.inputs['parent'].sv_get(default=None)
        objectsC = self.inputs['child'].sv_get()
        transforms = self.inputs['matr/vert'].sv_get()
        objects = bpy.data.objects
        #if any([x.name == self.name_node_generated_parent for x in objects]):
        ob = objects.get(self.name_node_generated_parent)
        #self.name_node_generated_parent = ob.name

        if ob:
            wipe_object(ob)

        # minimum requirements.
        if (not transforms) and (not objectsC):
            if ob:
                ob.dupli_type = 'NONE'
            return

        if not ob:
            name = self.name_node_generated_parent
            mesh = bpy.data.meshes.new(name + '_mesh')
            ob = bpy.data.objects.new(name, mesh)
            bpy.context.scene.objects.link(ob)

        # at this point there's a reference to an ob, and the mesh is empty.
        child = self.inputs['child'].sv_get()[0]
        #print('проверка',child)


        if transforms and transforms[0]:
            # -- this mode will face duplicate --
            # i expect this can be done faster using numpy
            # please view this only as exploratory

            if self.inputs['matr/vert'].links[0].from_socket.bl_idname == 'VerticesSocket':
                transforms = transforms[0]
                # -- this mode will vertex duplicate --
                ob.data.from_pydata(transforms, [], [])
                ob.dupli_type = 'VERTS'
                child.parent = ob

            elif self.inputs['matr/vert'].links[0].from_socket.bl_idname == 'MatrixSocket':
                sin, cos = math.sin, math.cos

                theta = 2 * math.pi / 3
                thetb = theta * 2
                ofs = 0.5 * math.pi + theta

                A = Vector((cos(0 + ofs), sin(0 + ofs), 0))
                B = Vector((cos(theta + ofs), sin(theta + ofs), 0))
                C = Vector((cos(thetb + ofs), sin(thetb + ofs), 0))

                verts = []
                add_verts = verts.extend

                num_matrices = len(transforms)
                for m in transforms:
                    M = matrix_sanitizer(m)
                    add_verts([(M * A)[:], (M * B)[:], (M * C)[:]])

                strides = range(0, num_matrices * 3, 3)
                faces = [[i, i + 1, i + 2] for i in strides]

                ob.data.from_pydata(verts, [], faces)
                ob.dupli_type = 'FACES'
                ob.use_dupli_faces_scale = self.scale
                child.parent = ob
Example #8
0
class SvProfileNodeMK3(bpy.types.Node, SverchCustomTreeNode, SvAnimatableNode):
    '''
    Triggers: svg-like 2d profiles
    Tooltip: Generate multiple parameteric 2d profiles using SVG like syntax

    SvProfileNode generates one or more profiles / elevation segments using;
    assignments, variables, and a string descriptor similar to SVG.

    This node expects simple input, or vectorized input.
    - sockets with no input are automatically 0, not None
    - The longest input array will be used to extend the shorter ones, using last value repeat.
    '''

    bl_idname = 'SvProfileNodeMK3'
    bl_label = 'Profile Parametric Mk3'
    bl_icon = 'SYNTAX_ON'

    axis_options = [("X", "X", "", 0), ("Y", "Y", "", 1), ("Z", "Z", "", 2)]

    selected_axis: EnumProperty(
        items=axis_options,
        update=updateNode,
        name="Type of axis",
        description="offers basic axis output vectors X|Y|Z",
        default="Z")

    def pointer_update(self, context):
        if self.file_pointer:
            self.filename = self.file_pointer.name
        else:
            self.filename = ""
        self.adjust_sockets()
        updateNode(self, context)

    filename: StringProperty(default="")
    file_pointer: PointerProperty(type=bpy.types.Text,
                                  poll=lambda s, o: True,
                                  update=pointer_update)

    x: BoolProperty(default=True)
    y: BoolProperty(default=True)

    precision: IntProperty(
        name="Precision",
        min=0,
        max=10,
        default=8,
        update=updateNode,
        description=
        "decimal precision of coordinates when generating profile from selection"
    )

    addnodes: BoolProperty(
        name="AddNodes",
        default=False,
        description="Lets add support nodes at pressing from selection button")

    curve_points_count: IntProperty(
        name="Curve points count",
        min=1,
        max=100,
        default=20,
        update=updateNode,
        description="Default number of points on curve segment")

    close_threshold: FloatProperty(
        name="X command threshold",
        min=0,
        max=1,
        default=0.0005,
        precision=6,
        update=updateNode,
        description=
        "If distance between first and last point is less than this, X command will remove the last point"
    )

    nurbs_out: BoolProperty(name="NURBS output",
                            description="Output NURBS curves",
                            default=False,
                            update=updateNode)

    concat_curves: BoolProperty(name="Concatenate",
                                description="Concatenate curves",
                                default=False,
                                update=updateNode)

    concat_tolerance: FloatProperty(name="Concat tolerance",
                                    min=0.0,
                                    default=0.0001,
                                    precision=6,
                                    update=updateNode)

    def draw_buttons(self, context, layout):
        self.draw_animatable_buttons(layout, icon_only=True)
        layout.prop(self, 'selected_axis', expand=True)

        row = layout.row(align=True)
        row.prop_search(self,
                        'file_pointer',
                        bpy.data,
                        'texts',
                        text='',
                        icon='TEXT')
        col = layout.column(align=True)
        row = col.row()
        do_text = row.operator('node.sverchok_profilizer_mk3',
                               text='from selection')
        do_text.nodename = self.name
        do_text.treename = self.id_data.name
        do_text.x = self.x
        do_text.y = self.y

    def draw_buttons_ext(self, context, layout):
        self.draw_buttons(context, layout)

        layout.prop(self, "close_threshold")

        layout.label(text='Curves output settings')
        layout.prop(self, 'nurbs_out', toggle=True)
        layout.prop(self, 'concat_curves', toggle=True)
        if self.concat_curves:
            layout.prop(self, 'concat_tolerance')

        layout.label(text="Profile Generator settings")
        layout.prop(self, "precision")
        layout.prop(self, "curve_points_count")
        row = layout.row(align=True)
        row.prop(self, "x", text='x-affect', expand=True)
        row.prop(self, "y", text='y-affect', expand=True)

        layout.label(text="Import Examples")
        layout.menu(SvProfileImportMenu.bl_idname)
        layout.prop(self, "addnodes", text='Auto add nodes')

        layout.label(text=f"||{self.filename}||")

    def sv_init(self, context):
        self.inputs.new('SvStringsSocket', "a")

        self.outputs.new('SvVerticesSocket', "Vertices")
        self.outputs.new('SvStringsSocket', "Edges")
        self.outputs.new('SvVerticesSocket', "Knots")
        self.outputs.new('SvStringsSocket', "KnotNames")
        self.outputs.new('SvCurveSocket', "Curve")

    def load_profile(self):
        if not self.filename:
            return None

        # we do not store stripped self.filename, else prop_search will shows it as read
        internal_file = bpy.data.texts[self.filename.strip()]
        f = internal_file.as_string()
        profile = parse_profile(f)
        return profile

    def get_variables(self):
        variables = set()
        profile = self.load_profile()
        if not profile:
            return variables

        for statement in profile:
            vs = statement.get_variables()
            variables.update(vs)

        for statement in profile:
            vs = statement.get_hidden_inputs()
            variables.difference_update(vs)

        return list(sorted(list(variables)))

    def get_optional_inputs(self, profile):
        result = set()
        if not profile:
            return result
        for statement in profile:
            vs = statement.get_optional_inputs()
            result.update(vs)
        return result

    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 sv_update(self):
        '''
        update analyzes the state of the node and returns if the criteria to start processing
        are not met.
        '''

        # keeping the file internal for now.
        if not (self.filename.strip() in bpy.data.texts):
            return

        self.adjust_sockets()

    def get_input(self):
        variables = self.get_variables()
        result = {}

        for var in variables:
            if var in self.inputs and self.inputs[var].is_linked:
                result[var] = self.inputs[var].sv_get()[0]
        return result

    def extend_out_verts(self, verts):
        if self.selected_axis == 'X':
            extend = lambda v: (0, v[0], v[1])
        elif self.selected_axis == 'Y':
            extend = lambda v: (v[0], 0, v[1])
        else:
            extend = lambda v: (v[0], v[1], 0)
        return list(map(extend, verts))

    def group_curves(self, curves):
        result = [[curves[0]]]
        tolerance = self.concat_tolerance
        for curve1, curve2 in zip(curves, curves[1:]):
            _, t_max_1 = curve1.get_u_bounds()
            t_min_2, _ = curve2.get_u_bounds()
            end1 = curve1.evaluate(t_max_1)
            begin2 = curve2.evaluate(t_min_2)
            distance = np.linalg.norm(begin2 - end1)
            if distance > tolerance:
                result.append([curve2])
            else:
                result[-1].append(curve2)
        return result

    def process(self):
        if not any(o.is_linked for o in self.outputs):
            return

        sync_pointer_and_stored_name(self, "file_pointer", "filename")

        profile = self.load_profile()
        optional_inputs = self.get_optional_inputs(profile)

        var_names = self.get_variables()
        self.debug("Var_names: %s; optional: %s", var_names, optional_inputs)
        inputs = self.get_input()

        result_vertices = []
        result_edges = []
        result_knots = []
        result_names = []
        result_curves = []

        if var_names:
            input_values = []
            for name in var_names:
                try:
                    input_values.append(inputs[name])
                except KeyError as e:
                    name = e.args[0]
                    if name not in optional_inputs:
                        if name in self.inputs:
                            raise SvNoDataError(self.inputs[name])
                        else:
                            self.adjust_sockets()
                            raise SvNoDataError(self.inputs[name])
                    else:
                        input_values.append([None])
            parameters = match_long_repeat(input_values)
        else:
            parameters = [[[]]]

        input_names = [
            socket.name for socket in self.inputs if socket.is_linked
        ]

        for values in zip(*parameters):
            variables = dict(zip(var_names, values))
            curves_form = Interpreter.NURBS if self.nurbs_out else None
            interpreter = Interpreter(self,
                                      input_names,
                                      curves_form=curves_form,
                                      z_axis=self.selected_axis)
            interpreter.interpret(profile, variables)
            verts = self.extend_out_verts(interpreter.vertices)
            result_vertices.append(verts)
            result_edges.append(interpreter.edges)
            knots = self.extend_out_verts(interpreter.knots)
            result_knots.append(knots)
            result_names.append([[name] for name in interpreter.knotnames])
            all_curves = interpreter.curves
            if self.concat_curves:
                new_curves = []
                for curves in self.group_curves(all_curves):
                    if self.nurbs_out:
                        curves = unify_curves_degree(curves)
                    curve = concatenate_curves(curves)
                    new_curves.append(curve)
                result_curves.append(new_curves)
            else:
                result_curves.append(all_curves)

        self.outputs['Vertices'].sv_set(result_vertices)
        self.outputs['Edges'].sv_set(result_edges)
        self.outputs['Knots'].sv_set(result_knots)
        self.outputs['KnotNames'].sv_set(result_names)
        if 'Curve' in self.outputs:
            self.outputs['Curve'].sv_set(result_curves)

    def load_from_json(self, node_data: dict, import_version: float):
        if 'profile' not in node_data:
            return  # looks like a node was empty when it was exported
        profile = node_data['profile']
        filename = node_data['params']['filename']

        bpy.data.texts.new(filename)
        bpy.data.texts[filename].clear()
        bpy.data.texts[filename].write(profile)
        self.file_pointer = bpy.data.texts[filename]

    def save_to_json(self, node_data: dict):
        if self.filename and self.filename.strip() in bpy.data.texts:
            text = bpy.data.texts[self.filename.strip()].as_string()
            node_data['profile'] = text
        else:
            self.warning("Unknown filename: {}".format(self.filename))

    def set_filename_to_match_file_pointer(self):
        self.file_pointer = self.file_pointer

    def set_pointer_from_filename(self):
        """ this function upgrades older versions of ProfileMK3 to the version that has self.file_pointer """
        if hasattr(self, "file_pointer") and not self.file_pointer:
            text = self.get_bpy_data_from_name(self.filename, bpy.data.texts)
            if text:
                self.file_pointer = text
class godot_node_list(bpy.types.PropertyGroup):
    name = StringProperty()
Example #10
0
class SvSocketAquisition:

    socket_map = {'outputs': 'to_socket', 'inputs': 'from_socket'}
    node_kind = StringProperty()

    def update(self):
        kind = self.node_kind
        if not kind:
            return

        monad = self.id_data
        if monad.bl_idname == "SverchCustomTreeType":
            return

        socket_list = getattr(self, kind)
        _socket = self.socket_map.get(kind) # from_socket, to_socket

        if len(socket_list) == 0:
            print('sockets wiped, skipped update')
            return

        if socket_list[-1].is_linked:

            # first switch socket type
            socket = socket_list[-1]
            if kind == "outputs":
                prop_name = monad.add_prop_from(socket)
            else:
                prop_name = ""

            cls = monad.update_cls()

            if kind == "outputs":
                new_name, new_type, prop_data = cls.input_template[-1]
            else:
                new_name, new_type = cls.output_template[-1]
                prop_data = {}

            new_socket = replace_socket(socket, new_type, new_name=new_name)
            if prop_name:
                new_socket.prop_name = prop_name

            # if no 'linked_socket.prop_name' then use 'linked_socket.name'


            for instance in monad.instances:
                sockets = getattr(instance, reverse_lookup[kind])
                new_socket = sockets.new(new_type, new_name)
                for name, value in prop_data.items():
                    setattr(new_socket, name, value)

            # add new dangling dummy
            socket_list.new('SvDummySocket', 'connect me')

    # stashing and repopulate are used for iojson

    def stash(self):
        socket_kinds = []
        for s in getattr(self, self.node_kind):
            if not s.bl_idname == 'SvDummySocket':
                socket_kinds.append([s.name, s.bl_idname])
        return socket_kinds

    def repopulate(self, socket_kinds):
        sockets = getattr(self, self.node_kind)
        sockets.remove(sockets[0])
        for idx, (s, stype) in enumerate(socket_kinds):
            # print('add', s, stype, 'to', self.name)
            sockets.new(stype, s)
Example #11
0
class ListJoinNode(bpy.types.Node, SverchCustomTreeNode):
    ''' ListJoin node '''
    bl_idname = 'ListJoinNode'
    bl_label = 'List Join'
    bl_icon = 'OUTLINER_OB_EMPTY'
    sv_icon = 'SV_LIST_JOIN'

    JoinLevel: IntProperty(
        name='JoinLevel', description='Choose join level of data (see help)',
        default=1, min=1, update=updateNode)

    mix_check: BoolProperty(
        name='mix', description='Grouping similar to zip()',
        default=False, update=updateNode)

    wrap_check: BoolProperty(
        name='wrap', description='Grouping similar to append(list)',
        default=False, update=updateNode)

    numpy_mode: BoolProperty(
        name='NumPy Mode', description='better to work with lists of NumPy arrays',
        default=False, update=updateNode)

    typ: StringProperty(name='typ', default='')
    newsock: BoolProperty(name='newsock', default=False)


    base_name = 'data '
    multi_socket_type = 'SvStringsSocket'

    def sv_init(self, context):
        self.inputs.new('SvStringsSocket', 'data')
        self.outputs.new('SvStringsSocket', 'data')

    def draw_buttons(self, context, layout):

        layout.prop(self, "mix_check", text="mix")
        if not self.numpy_mode:
            layout.prop(self, "wrap_check", text="wrap")
        layout.prop(self, "JoinLevel", text="JoinLevel lists")

    def draw_buttons_ext(self, context, layout):
        self.draw_buttons(context, layout)
        layout.prop(self, "numpy_mode", toggle=False, text='NumPy mode')

    def rclick_menu(self, context, layout):
        self.draw_buttons(context, layout)
        layout.prop(self, "numpy_mode", toggle=True, text='NumPy mode')


    def sv_update(self):

        if len(self.outputs) > 0:
            multi_socket(self, min=1)
        self.set_output_socketype([sock.other.bl_idname for sock in self.inputs if sock.links and sock.other])

    def process(self):

        if not self.outputs['data'].links:
            return

        slots = []
        for socket in self.inputs:
            if socket.is_linked and socket.links:
                slots.append(socket.sv_get())
        if len(slots) == 0:
            return

        if self.numpy_mode:
            if self.outputs[0].bl_idname == 'SvVerticesSocket':
                min_axis = 2
            else:
                min_axis = 1
            depth = levels_of_list_or_np(slots[0])
            true_depth = depth - min_axis
            result = numpy_join(slots, self.JoinLevel, self.mix_check, true_depth)
        else:
            result = python_join(slots, self.JoinLevel, self.mix_check, self.wrap_check)

        self.outputs[0].sv_set(result)

    def set_output_socketype(self, slot_bl_idnames):
        """
        1) if the input sockets are a mixed bag of bl_idnames we convert the output socket
        to a generic SvStringsSocket type
        2) if all input sockets where sv_get is successful are of identical bl_idname
        then set the output socket type to match that.
        3) no op if current output socket matches proposed new socket type.
        """

        if not slot_bl_idnames:
            return

        num_bl_idnames = len(set(slot_bl_idnames))
        new_socket_type = slot_bl_idnames[0] if num_bl_idnames == 1 else "SvStringsSocket"

        if self.outputs[0].bl_idname != new_socket_type:
            self.outputs[0].replace_socket(new_socket_type)

    def draw_label(self):
        """ this gives quick param display for when the node is minimzed """
        mixing = "M" if self.mix_check else ""
        wrapping = "W" if self.wrap_check and not self.numpy_mode else ""
        numpy_m = "NP " if self.numpy_mode else ""
        level = str(self.JoinLevel)
        fstr = " Lv={0} {1}{2}{3}".format(level, numpy_m, mixing, wrapping)
        return self.name + fstr
Example #12
0
class SvMonadGenericNode(Node, SverchCustomTreeNode,  monad_def.SvGroupNodeExp):
    bl_idname = 'SvMonadGenericNode'
    bl_label = 'Group'
    bl_icon = 'OUTLINER_OB_EMPTY'

    data_storage = StringProperty()
    cls_bl_idname = StringProperty(update=call_init)

    @property
    def input_template(self):
        if not self.data_storage:
            return []
        data = ast.literal_eval(self.data_storage)
        return data.get("input_template", {})

    @input_template.setter
    def input_template(self, value):
        if self.data_storage:
            data = ast.literal_eval(self.data_storage)
        else:
            data = {}
        data["input_template"] = value
        self.data_storage = str(data)
        self.inputs.clear()
        for socket_name, socket_bl_idname, _ in value:
            self.inputs.new(socket_bl_idname, socket_name)

    @property
    def output_template(self):
        if not self.data_storage:
            return []
        data = ast.literal_eval(self.data_storage)
        return data.get("output_template", [])

    @output_template.setter
    def output_template(self, value):
        if self.data_storage:
            data = ast.literal_eval(self.data_storage)
        else:
            data = {}
        data["output_template"] = value
        self.data_storage = str(data)
        self.outputs.clear()
        for socket_name, socket_bl_idname in value:
            self.outputs.new(socket_bl_idname, socket_name)

    @property
    def monad(self):
        if not self.cls_bl_idname:
            return None

        for monad in bpy.data.node_groups:
            if hasattr(monad, "cls_bl_idname"):
                if monad.cls_bl_idname == self.cls_bl_idname:
                    return monad

        return None

    def sv_init(self, context):
        self.use_custom_color = True
        self.color = monad_def.MONAD_COLOR
Example #13
0
class SvTextOutNodeMK2(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: Text Out to datablock
    Tooltip: Quickly write data from NodeView to text datablock
    """
    bl_idname = 'SvTextOutNodeMK2'
    bl_label = 'Text out+'
    bl_icon = 'COPYDOWN'

    sv_modes = [('compact', 'Compact', 'Using str()', 1),
                ('pretty', 'Pretty', 'Using pretty print', 2)]

    json_modes = [('compact', 'Compact', 'Minimal', 1),
                  ('pretty', 'Pretty', 'Indent and order', 2)]

    csv_dialects = [('excel', 'Excel', 'Standard excel', 1),
                    ('excel-tab', 'Excel tabs', 'Excel tab format', 2),
                    ('unix', 'Unix', 'Unix standard', 3)]

    def change_mode(self, context):
        self.inputs.clear()

        if self.text_mode == 'CSV':
            self.inputs.new('StringsSocket', 'Col 0')
            self.base_name = 'Col '
        elif self.text_mode == 'JSON':
            self.inputs.new('StringsSocket', 'Data 0')
            self.base_name = 'Data '
        elif self.text_mode == 'SV':
            self.inputs.new('StringsSocket', 'Data')

    text: StringProperty()

    text_mode: EnumProperty(items=text_modes,
                            default='CSV',
                            update=change_mode,
                            name="Text format")
    csv_dialect: EnumProperty(items=csv_dialects,
                              default='excel',
                              name="Dialect")
    sv_mode: EnumProperty(items=sv_modes, default='compact', name="Format")
    json_mode: EnumProperty(items=json_modes, default='pretty', name="Format")

    append: BoolProperty(default=False, description="Append to output file")
    base_name: StringProperty(name='base_name', default='Col ')
    multi_socket_type: StringProperty(name='multi_socket_type',
                                      default='StringsSocket')

    autodump: BoolProperty(default=False,
                           description="autodump",
                           name="auto dump")

    def sv_init(self, context):
        self.inputs.new('StringsSocket', 'Col 0')

    def draw_buttons(self, context, layout):

        addon = context.preferences.addons.get(sverchok.__name__)
        over_sized_buttons = addon.preferences.over_sized_buttons

        col = layout.column(align=True)
        col.prop(self, 'autodump', toggle=True)
        row = col.row(align=True)
        row.prop_search(self, 'text', bpy.data, 'texts', text="Write")
        row.operator("text.new", icon="ZOOMIN", text='')

        row = col.row(align=True)
        row.prop(self, 'text_mode', expand=True)

        row = col.row(align=True)
        if self.text_mode == 'CSV':
            row.prop(self, 'csv_dialect')
        elif self.text_mode == 'SV':
            row.prop(self, 'sv_mode', expand=True)
        elif self.text_mode == 'JSON':
            row.prop(self, 'json_mode', expand=True)

        if not self.autodump:
            col2 = col.column(align=True)
            row = col2.row(align=True)
            row.scale_y = 4.0 if over_sized_buttons else 1
            row.operator(TEXT_IO_CALLBACK, text='D U M P').fn_name = 'dump'
            col2.prop(self, 'append', "Append")

    def update_socket(self, context):
        self.update()

    def process(self):
        if self.text_mode in {'CSV', 'JSON'}:
            multi_socket(self, min=1)

        if self.autodump:
            self.append = False
            self.dump()

    # build a string with data from sockets
    def dump(self):
        out = self.get_data()
        if len(out) == 0:
            return False

        if not self.append:
            bpy.data.texts[self.text].clear()
        bpy.data.texts[self.text].write(out)
        self.color = READY_COLOR

        return True

    def get_data(self):
        out = ""
        if self.text_mode == 'CSV':
            out = get_csv_data(node=self)
        elif self.text_mode == 'JSON':
            out = get_json_data(node=self)
        elif self.text_mode == 'SV':
            out = get_sv_data(node=self)
        return out
Example #14
0
class myfacemask_adapt_mask(Operator):
    bl_idname = "object.myfacemask_adapt_mask"
    bl_label = "Adapt Mask"
    bl_description = ("Extract mask border based on red area")
    bl_options = {'REGISTER', 'UNDO'}

    use_modifiers: BoolProperty(name="Use Modifiers",
                                default=True,
                                description="Apply all the modifiers")

    min_iso: FloatProperty(name="Min Value",
                           default=0.,
                           soft_min=0,
                           soft_max=1,
                           description="Minimum weight value")
    max_iso: FloatProperty(name="Max Value",
                           default=1,
                           soft_min=0,
                           soft_max=1,
                           description="Maximum weight value")
    n_curves: IntProperty(name="Curves",
                          default=10,
                          soft_min=1,
                          soft_max=100,
                          description="Number of Contour Curves")

    in_displace: FloatProperty(name="Displace A",
                               default=0,
                               soft_min=-10,
                               soft_max=10,
                               description="Pattern displace strength")
    out_displace: FloatProperty(name="Displace B",
                                default=2,
                                soft_min=-10,
                                soft_max=10,
                                description="Pattern displace strength")

    in_steps: IntProperty(name="Steps A",
                          default=1,
                          min=0,
                          soft_max=10,
                          description="Number of layers to move inwards")
    out_steps: IntProperty(name="Steps B",
                           default=1,
                           min=0,
                           soft_max=10,
                           description="Number of layers to move outwards")
    limit_z: BoolProperty(name="Limit Z",
                          default=False,
                          description="Limit Pattern in Z")

    merge: BoolProperty(name="Merge Vertices",
                        default=True,
                        description="Merge points")
    merge_thres: FloatProperty(name="Merge Threshold",
                               default=0.01,
                               min=0,
                               soft_max=1,
                               description="Minimum Curve Radius")

    bevel_depth: FloatProperty(name="Bevel Depth",
                               default=0,
                               min=0,
                               soft_max=1,
                               description="")
    min_bevel_depth: FloatProperty(name="Min Bevel Depth",
                                   default=0.1,
                                   min=0,
                                   soft_max=1,
                                   description="")
    max_bevel_depth: FloatProperty(name="Max Bevel Depth",
                                   default=1,
                                   min=0,
                                   soft_max=1,
                                   description="")
    remove_open_curves: BoolProperty(name="Remove Open Curves",
                                     default=False,
                                     description="Remove Open Curves")

    vertex_group_pattern: StringProperty(
        name="Displace",
        default='',
        description="Vertex Group used for pattern displace")

    vertex_group_bevel: StringProperty(name="Bevel",
                                       default='',
                                       description="Variable Bevel depth")

    object_name: StringProperty(name="Active Object",
                                default='',
                                description="")

    try:
        vg_name = bpy.context.object.vertex_groups.active.name
    except:
        vg_name = ''

    vertex_group_contour: StringProperty(
        name="Contour",
        default=vg_name,
        description="Vertex Group used for contouring")
    clean_distance: FloatProperty(name="Clean Distance",
                                  default=2,
                                  min=0,
                                  soft_max=10,
                                  description="Remove short segments")

    @classmethod
    def poll(cls, context):
        ob = context.object
        return ob and len(ob.vertex_groups) > 0 and ob.mode == 'WEIGHT_PAINT'

    def draw(self, context):
        if not context.object.type == 'CURVE':
            self.object_name = context.object.name
        ob = bpy.data.objects[self.object_name]
        if self.vertex_group_contour not in [
                vg.name for vg in ob.vertex_groups
        ]:
            self.vertex_group_contour = ob.vertex_groups.active.name
        layout = self.layout
        col = layout.column(align=True)
        col.prop(self, "use_modifiers")
        col.label(text="Contour Curves:")
        col.prop_search(self,
                        'vertex_group_contour',
                        ob,
                        "vertex_groups",
                        text='')

        col.label(text='Clean Curves:')
        col.prop(self, 'clean_distance')
        #col.prop(self,'remove_open_curves')

    def execute(self, context):
        start_time = timeit.default_timer()
        try:
            check = context.object.vertex_groups[0]
        except:
            self.report({'ERROR'}, "The object doesn't have Vertex Groups")
            return {'CANCELLED'}
        bpy.ops.object.vertex_group_smooth(repeat=5)

        ob0 = context.object  #bpy.data.objects[self.object_name]

        dg = context.evaluated_depsgraph_get()
        ob = ob0  #.evaluated_get(dg)
        me0 = ob.data

        # generate new bmesh
        bm = bmesh.new()
        bm.from_mesh(me0)
        n_verts = len(bm.verts)

        # store weight values
        try:
            weight = get_weight_numpy(ob.vertex_groups.active,
                                      len(me0.vertices))
        except:
            bm.free()
            self.report({'ERROR'},
                        "Please select a Vertex Group for contouring")
            return {'CANCELLED'}

        try:
            pattern_weight = get_weight_numpy(
                ob.vertex_groups[self.vertex_group_pattern], len(me0.vertices))
        except:
            #self.report({'WARNING'}, "There is no Vertex Group assigned to the pattern displace")
            pattern_weight = np.zeros(len(me0.vertices))

        variable_bevel = False
        try:
            bevel_weight = get_weight_numpy(
                ob.vertex_groups[self.vertex_group_bevel], len(me0.vertices))
            variable_bevel = True
        except:
            bevel_weight = np.ones(len(me0.vertices))

        #filtered_edges = bm.edges
        total_verts = np.zeros((0, 3))
        total_segments = []  # np.array([])

        # start iterate contours levels
        vertices, normals = get_vertices_and_normals_numpy(me0)
        filtered_edges = get_edges_id_numpy(me0)

        faces_weight = [
            np.array([weight[v] for v in p.vertices]) for p in me0.polygons
        ]
        fw_min = np.array([np.min(fw) for fw in faces_weight])
        fw_max = np.array([np.max(fw) for fw in faces_weight])

        bm_faces = np.array(bm.faces)

        step_time = timeit.default_timer()
        for c in range(1):
            min_iso = min(0, 1)
            max_iso = max(0, 1)
            iso_val = 0.5

            # remove passed faces
            bool_mask = iso_val < fw_max
            bm_faces = bm_faces[bool_mask]
            fw_min = fw_min[bool_mask]
            fw_max = fw_max[bool_mask]

            # mask faces
            bool_mask = fw_min < iso_val
            faces_mask = bm_faces[bool_mask]

            count = len(total_verts)

            new_filtered_edges, edges_index, verts, bevel = contour_edges_pattern(
                self, c, len(total_verts), iso_val, vertices, normals,
                filtered_edges, weight, pattern_weight, bevel_weight)

            if verts[0, 0] == None: continue
            else: filtered_edges = new_filtered_edges
            edges_id = {}
            for i, id in enumerate(edges_index):
                edges_id[id] = i + count

            if len(verts) == 0: continue

            # finding segments
            segments = []
            for f in faces_mask:
                seg = []
                for e in f.edges:
                    try:
                        seg.append(edges_id[e.index])
                        if len(seg) == 2:
                            segments.append(seg)
                            seg = []
                    except:
                        pass

            total_segments = total_segments + segments
            total_verts = np.concatenate((total_verts, verts))

        if len(total_segments) > 0:
            step_time = timeit.default_timer()
            try:
                ordered_points = find_curves(total_segments, len(total_verts))
            except:
                self.report({
                    'ERROR'
                }, "Something goes wrong, try to fill the inner parts, or to smooth the weight map"
                            )
                return {'CANCELLED'}

            max_len = 0
            longer_curve = [ordered_points[0]]
            for crv in ordered_points:
                pts = total_verts[np.array(crv, dtype='int')]
                size_x = pts.max(axis=0)[0] - pts.min(axis=0)[0]
                if max_len < size_x:
                    max_len = size_x
                    longer_curve = [crv]
            step_time = timeit.default_timer()
            crv = curve_from_pydata(total_verts,
                                    longer_curve,
                                    'ContourCurve',
                                    self.remove_open_curves,
                                    merge_distance=self.clean_distance)
            context.view_layer.objects.active = crv
            crv.parent = ob0

            crv.select_set(True)
            ob0.select_set(False)
            crv.matrix_world = ob0.matrix_world
        else:
            bm.free()
            self.report({'ERROR'}, "Please define the area on the face")
            return {'CANCELLED'}
        bm.free()

        bpy.data.collections['MyFaceMask'].hide_viewport = False

        bpy.ops.object.convert(target='MESH')
        curve_object = context.object
        curve_object.hide_viewport = True

        n_verts = len(curve_object.data.vertices)
        matr = curve_object.matrix_world
        verts = [matr @ v.co for v in curve_object.data.vertices]
        mid_point = Vector((0, 0, 0))
        for v in verts:
            mid_point += v
        try:
            mid_point /= n_verts
        except:
            self.report({'ERROR'}, "Please define the area on the face")
            return {'CANCELLED'}
        nor_vec = Vector((0, 0, 0))
        for i in range(n_verts - 1):
            v0 = verts[i] - mid_point
            v1 = verts[i + 1] - mid_point
            nor_vec += v0.cross(v1)
        nor_vec.normalize()
        if nor_vec.y > 0:
            nor_vec *= -1

        filter = bpy.data.objects['Filter']
        filter.location = mid_point + nor_vec * 60
        filter.rotation_euler[0] = atan2(cos(nor_vec.y), sin(nor_vec.z)) + pi
        matr = filter.matrix_local
        filter.location -= nor_vec.normalized().cross(Vector((1, 0, 0))) * 15
        filter.location.x = 0

        ### adapt mask
        mask_srf = bpy.data.objects['Mask_Surface']
        mask_srf.modifiers['curve_project_01'].target = curve_object
        #mask_srf.modifiers['curve_project_02'].target = curve_object
        mask_srf.modifiers['avoid_face_intersections'].target = ob0
        mask_srf.modifiers['adapt_to_face'].target = ob0
        mask_srf.modifiers['adapt_to_face_02'].target = ob0

        print("Contour Curves, total time: " +
              str(timeit.default_timer() - start_time) + " sec")
        return {'FINISHED'}
class SvListModifierNode(bpy.types.Node, SverchCustomTreeNode):
    ''' List Modifier'''
    bl_idname = 'SvListModifierNode'
    bl_label = 'List Modifier'
    bl_icon = 'MODIFIER'
    sv_icon = 'SV_LIST_MODIFIER'

    mode_items = [(name, name, "", idx) for _, idx, name, _ in node_item_list]

    func_: EnumProperty(
        name="Modes",
        description="Mode Choices",
        default=SET, items=mode_items,
        update=updateNode
    )

    listify: BoolProperty(
        default=True,
        description='Output lists or proper sets',
        update=updateNode
    )

    help_url: StringProperty(default='list_main/list_modifier')

    def draw_buttons(self, context, layout):
        layout.prop(self, "func_", text='')
        layout.prop(self, "listify", text='output as list')

    def sv_init(self, context):
        self.inputs.new('SvStringsSocket', "Data1")
        self.inputs.new('SvStringsSocket', "Data2")        
        self.outputs.new('SvStringsSocket', "Result")

    def draw_label(self):
        return self.func_

    def process(self):
        inputs = self.inputs
        outputs = self.outputs

        if not outputs[0].is_linked:
            return
        
        unary = (num_inputs[self.func_] == 1)
        f = self.get_f(unary)

        if unary:
            if inputs['Data1'].is_linked:
                data1 = inputs['Data1'].sv_get()
            elif inputs['Data2'].is_linked:
                data1 = inputs['Data2'].sv_get()
            else:
                return
            out = f(data1)
        else:
            data1 = inputs['Data1'].sv_get()
            data2 = inputs['Data2'].sv_get()
            out = f(data1, data2)
            # params = match_long_repeat([data1, data2])
            # out = f(*params)

        outputs[0].sv_set(out)

    def get_f(self, unary):
        operation = func_dict[self.func_]

        do_post = (self.func_ in SET_OPS) and self.listify
        post_process = list if do_post else lambda x: x # identity function

        if unary:
            def f(d):
                if isinstance(d[0], (int, float)):
                    return post_process(operation(d))
                else:
                    return [f(x) for x in d]
        else: 
            def f(a, b):
                if isinstance(a[0], (int, float)):
                    return post_process(operation(a, b))
                else:
                    return [f(*_) for _ in zip(a, b)]

        return f
Example #16
0
class DomainStatsProperties(bpy.types.PropertyGroup):
    conv = vcu.convert_attribute_to_28

    cache_info_type = EnumProperty(
        name="Cache Info Display Mode",
        description="Type of cache info to display",
        items=types.cache_info_modes,
        default='CACHE_INFO',
        update=lambda self, context: self._update_cache_info_type(context),
    )
    exec(conv("cache_info_type"))
    current_info_frame = IntProperty(
        name="Frame",
        description="Select frame number",
        min=0,
        default=0,
        update=lambda self, context: self._update_current_info_frame(context),
    )
    exec(conv("current_info_frame"))
    lock_info_frame_to_timeline = BoolProperty(
        name="Lock To Timeline",
        description="Set frame number to current frame in timeline",
        default=True,
        update=lambda self, context: self._update_lock_info_frame_to_timeline(
            context),
    )
    exec(conv("lock_info_frame_to_timeline"))
    temp_directory = vcu.get_blender_preferences(
        bpy.context).filepaths.temporary_directory
    csv_save_filepath = StringProperty(name="",
                                       default=os.path.join(
                                           temp_directory,
                                           "flip_fluid_stats.csv"),
                                       subtype='FILE_PATH')
    exec(conv("csv_save_filepath"))
    csv_region_format = EnumProperty(
        name="Region Format",
        description="CSV region formatting",
        items=types.csv_regions,
        default='CSV_REGION_US',
    )
    exec(conv("csv_region_format"))

    stats_filename = bpy.props.StringProperty(default='flipstats.data')
    exec(conv("stats_filename"))
    is_stats_current = bpy.props.BoolProperty(default=False)
    exec(conv("is_stats_current"))

    # Cache Info
    cache_info_simulation_stats_expanded = BoolProperty(default=True)
    exec(conv("cache_info_simulation_stats_expanded"))
    cache_info_timing_stats_expanded = BoolProperty(default=True)
    exec(conv("cache_info_timing_stats_expanded"))
    cache_info_mesh_stats_expanded = BoolProperty(default=True)
    exec(conv("cache_info_mesh_stats_expanded"))
    is_cache_info_available = BoolProperty(default=False)
    exec(conv("is_cache_info_available"))
    num_cache_frames = IntProperty(default=-1)
    exec(conv("num_cache_frames"))
    estimated_frame_speed = FloatProperty(default=-1)
    exec(conv("estimated_frame_speed"))
    estimated_time_remaining = IntProperty(default=-1)
    exec(conv("estimated_time_remaining"))
    estimated_time_remaining_timestamp = IntProperty(default=-1)
    exec(conv("estimated_time_remaining_timestamp"))
    is_estimated_time_remaining_available = BoolProperty(default=False)
    exec(conv("is_estimated_time_remaining_available"))
    cache_bytes = PointerProperty(type=ByteProperty)
    exec(conv("cache_bytes"))

    # Frame Info
    frame_info_simulation_stats_expanded = BoolProperty(default=True)
    exec(conv("frame_info_simulation_stats_expanded"))
    frame_info_timing_stats_expanded = BoolProperty(default=True)
    exec(conv("frame_info_timing_stats_expanded"))
    frame_info_mesh_stats_expanded = BoolProperty(default=True)
    exec(conv("frame_info_mesh_stats_expanded"))
    display_frame_viscosity_timing_stats = BoolProperty(default=False)
    exec(conv("display_frame_viscosity_timing_stats"))
    display_frame_diffuse_timing_stats = BoolProperty(default=False)
    exec(conv("display_frame_diffuse_timing_stats"))
    display_frame_diffuse_particle_stats = BoolProperty(default=False)
    exec(conv("display_frame_diffuse_particle_stats"))
    is_frame_info_available = bpy.props.BoolProperty(default=False)
    exec(conv("is_frame_info_available"))
    frame_info_id = IntProperty(default=-1)
    exec(conv("frame_info_id"))
    frame_substeps = IntProperty(default=-1)
    exec(conv("frame_substeps"))
    frame_delta_time = FloatProperty(default=0.0)
    exec(conv("frame_delta_time"))
    frame_fluid_particles = IntProperty(default=-1)
    exec(conv("frame_fluid_particles"))
    frame_diffuse_particles = IntProperty(default=-1)
    exec(conv("frame_diffuse_particles"))

    # Mesh Info
    surface_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("surface_mesh"))
    preview_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("preview_mesh"))
    surfaceblur_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("surfaceblur_mesh"))
    foam_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("foam_mesh"))
    bubble_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("bubble_mesh"))
    spray_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("spray_mesh"))
    dust_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("dust_mesh"))
    foamblur_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("foamblur_mesh"))
    bubbleblur_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("bubbleblur_mesh"))
    sprayblur_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("sprayblur_mesh"))
    dustblur_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("dustblur_mesh"))
    particle_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("particle_mesh"))
    obstacle_mesh = PointerProperty(type=MeshStatsProperties)
    exec(conv("obstacle_mesh"))

    # Time Info
    time_mesh = PointerProperty(type=TimeStatsProperties)
    exec(conv("time_mesh"))
    time_advection = PointerProperty(type=TimeStatsProperties)
    exec(conv("time_advection"))
    time_particles = PointerProperty(type=TimeStatsProperties)
    exec(conv("time_particles"))
    time_pressure = PointerProperty(type=TimeStatsProperties)
    exec(conv("time_pressure"))
    time_diffuse = PointerProperty(type=TimeStatsProperties)
    exec(conv("time_diffuse"))
    time_viscosity = PointerProperty(type=TimeStatsProperties)
    exec(conv("time_viscosity"))
    time_objects = PointerProperty(type=TimeStatsProperties)
    exec(conv("time_objects"))
    time_other = PointerProperty(type=TimeStatsProperties)
    exec(conv("time_other"))

    def register_preset_properties(self, registry, path):
        add = registry.add_property
        add(path + ".cache_info_type", "Info Type", group_id=0)
        add(path + ".lock_info_frame_to_timeline",
            "Lock Frame to Timeline",
            group_id=0)
        add(path + ".csv_region_format", "CSV Region Format", group_id=0)

    def format_long_time(self, t):
        m, s = divmod(t, 60)
        h, m = divmod(m, 60)
        return "%d:%02d:%02d" % (h, m, s)

    def get_time_remaining_string(self, context):
        ret_str = ""
        if self.is_estimated_time_remaining_available:
            now = self.get_timestamp()
            dt = now - self.estimated_time_remaining_timestamp
            time_remaining = self.estimated_time_remaining - dt
            time_remaining = max(0, time_remaining)
            ret_str = self.format_long_time(time_remaining)
        return ret_str

    def reset_stats_values(self):
        prop_names = [
            "frame_info_id", "frame_substeps", "frame_delta_time",
            "frame_fluid_particles", "frame_diffuse_particles", "surface_mesh",
            "preview_mesh", "surfaceblur_mesh", "foam_mesh", "bubble_mesh",
            "spray_mesh", "dust_mesh", "foamblur_mesh", "bubbleblur_mesh",
            "sprayblur_mesh", "dustblur_mesh", "particle_mesh",
            "obstacle_mesh", "time_mesh", "time_advection", "time_particles",
            "time_pressure", "time_diffuse", "time_viscosity", "time_objects",
            "time_other"
        ]

        for name in prop_names:
            self.property_unset(name)

    def reset_time_remaining(self):
        self.is_estimated_time_remaining_available = False

    def refresh_stats(self):
        dprops = bpy.context.scene.flip_fluid.get_domain_properties()
        if not dprops:
            self.is_cache_info_available = False
            return

        cache_directory = dprops.cache.get_cache_abspath()
        statsfile = os.path.join(cache_directory, self.stats_filename)
        if not os.path.isfile(statsfile):
            self.is_cache_info_available = False
            return
        self.is_cache_info_available = True

        if self.cache_info_type == "FRAME_INFO":
            if self.lock_info_frame_to_timeline:
                self.current_info_frame = bpy.context.scene.frame_current
            else:
                self._update_frame_stats()
        elif self.cache_info_type == "CACHE_INFO":
            self._update_cache_stats()
        self.is_stats_current = True

    def scene_update_post(self, scene):
        if self.is_stats_current:
            return
        self.refresh_stats()

    def frame_change_post(self, scene, depsgraph=None):
        if self.cache_info_type == "FRAME_INFO" and self.lock_info_frame_to_timeline:
            if self.current_info_frame != scene.frame_current:
                self.current_info_frame = scene.frame_current

    def load_post(self):
        self.refresh_stats()

    def get_timestamp(self):
        dt = datetime.datetime.now() - datetime.datetime.utcfromtimestamp(0)
        return int(dt.total_seconds())

    def _update_current_info_frame(self, context):
        self._update_frame_stats()

    def _update_cache_info_type(self, context):
        if self.cache_info_type == 'CACHE_INFO':
            self._update_cache_stats()
        elif self.cache_info_type == 'FRAME_INFO':
            if self.lock_info_frame_to_timeline:
                if self.current_info_frame != context.scene.frame_current:
                    self.current_info_frame = context.scene.frame_current
            self._update_frame_stats()

    def _update_lock_info_frame_to_timeline(self, context):
        if self.lock_info_frame_to_timeline:
            self.current_info_frame = context.scene.frame_current

    def _update_frame_stats(self):
        dprops = bpy.context.scene.flip_fluid.get_domain_properties()
        if dprops is None:
            return

        frameno = self.current_info_frame
        cache_directory = dprops.cache.get_cache_abspath()
        statsfile = os.path.join(cache_directory, self.stats_filename)
        if not os.path.isfile(statsfile):
            self.is_frame_info_available = False
            return

        with open(statsfile, 'r') as f:
            statsdata = json.loads(f.read())

        framekey = str(self.current_info_frame)
        if not framekey in statsdata:
            self.is_frame_info_available = False
            return

        data = statsdata[framekey]
        self.is_frame_info_available = True
        self.frame_info_id = data['frame']
        self.frame_substeps = data['substeps']
        self.frame_delta_time = data['delta_time']
        self.frame_fluid_particles = data['fluid_particles']
        self.frame_diffuse_particles = data['diffuse_particles']

        self._set_mesh_stats_data(self.surface_mesh, data['surface'])
        self._set_mesh_stats_data(self.preview_mesh, data['preview'])
        self._set_mesh_stats_data(self.surfaceblur_mesh, data['surfaceblur'])
        self._set_mesh_stats_data(self.foam_mesh, data['foam'])
        self._set_mesh_stats_data(self.bubble_mesh, data['bubble'])
        self._set_mesh_stats_data(self.spray_mesh, data['spray'])

        if 'dust' in data:
            # If statement to support older caches that do not have a dust entry
            self._set_mesh_stats_data(self.dust_mesh, data['dust'])

        self._set_mesh_stats_data(self.foamblur_mesh, data['foamblur'])
        self._set_mesh_stats_data(self.bubbleblur_mesh, data['bubbleblur'])
        self._set_mesh_stats_data(self.sprayblur_mesh, data['sprayblur'])

        if 'dustblur' in data:
            # If statement to support older caches that do not have a dustblur entry
            self._set_mesh_stats_data(self.dustblur_mesh, data['dustblur'])

        self._set_mesh_stats_data(self.particle_mesh, data['particles'])
        self._set_mesh_stats_data(self.obstacle_mesh, data['obstacle'])

        total_time = max(data['timing']['total'], 1e-6)
        time_other = (total_time - data['timing']['mesh'] -
                      data['timing']['advection'] -
                      data['timing']['particles'] -
                      data['timing']['pressure'] - data['timing']['diffuse'] -
                      data['timing']['viscosity'] - data['timing']['objects'])
        time_other = max(0.0, time_other)

        self.time_mesh.set_time_pct(100 * data['timing']['mesh'] / total_time)
        self.time_advection.set_time_pct(100 * data['timing']['advection'] /
                                         total_time)
        self.time_particles.set_time_pct(100 * data['timing']['particles'] /
                                         total_time)
        self.time_pressure.set_time_pct(100 * data['timing']['pressure'] /
                                        total_time)
        self.time_diffuse.set_time_pct(100 * data['timing']['diffuse'] /
                                       total_time)
        self.time_viscosity.set_time_pct(100 * data['timing']['viscosity'] /
                                         total_time)
        self.time_objects.set_time_pct(100 * data['timing']['objects'] /
                                       total_time)
        self.time_other.set_time_pct(100 * time_other / total_time)

        precision = 2
        self.time_mesh.time = round(data['timing']['mesh'], precision)
        self.time_advection.time = round(data['timing']['advection'],
                                         precision)
        self.time_particles.time = round(data['timing']['particles'],
                                         precision)
        self.time_pressure.time = round(data['timing']['pressure'], precision)
        self.time_diffuse.time = round(data['timing']['diffuse'], precision)
        self.time_viscosity.time = round(data['timing']['viscosity'],
                                         precision)
        self.time_objects.time = round(data['timing']['objects'], precision)
        self.time_other.time = round(time_other, precision)

        self.display_frame_viscosity_timing_stats = False
        self.display_frame_diffuse_timing_stats = False
        self.display_frame_diffuse_particle_stats = False
        for key in statsdata.keys():
            if key.isdigit():
                if statsdata[key]['diffuse_particles'] > 0.0:
                    self.display_frame_diffuse_particle_stats = True
                    break
        for key in statsdata.keys():
            if key.isdigit():
                if statsdata[key]['timing']['viscosity'] > 0.0:
                    self.display_frame_viscosity_timing_stats = True
                    break
        for key in statsdata.keys():
            if key.isdigit():
                if statsdata[key]['timing']['diffuse'] > 0.0:
                    self.display_frame_diffuse_timing_stats = True
                    break

        self._update_cache_size(statsdata)

    def _set_mesh_stats_data(self, mesh_stats, mesh_stats_dict):
        mesh_stats.enabled = mesh_stats_dict['enabled']
        mesh_stats.verts = mesh_stats_dict['vertices']
        mesh_stats.faces = mesh_stats_dict['triangles']
        mesh_stats.bytes.set(mesh_stats_dict['bytes'])

    def _update_cache_size(self, cachedata):
        cache_size = 0
        for key in cachedata.keys():
            if not key.isdigit():
                continue
            fdata = cachedata[key]
            if fdata['surface']['enabled']:
                cache_size += fdata['surface']['bytes']
            if fdata['preview']['enabled']:
                cache_size += fdata['preview']['bytes']
            if fdata['surfaceblur']['enabled']:
                cache_size += fdata['surfaceblur']['bytes']
            if fdata['foam']['enabled']:
                cache_size += fdata['foam']['bytes']
            if fdata['bubble']['enabled']:
                cache_size += fdata['bubble']['bytes']
            if fdata['spray']['enabled']:
                cache_size += fdata['spray']['bytes']
            if 'dust' in fdata and fdata['dust'][
                    'enabled']:  # If statement to support caches without a dust entry
                cache_size += fdata['dust']['bytes']
            if fdata['foamblur']['enabled']:
                cache_size += fdata['foamblur']['bytes']
            if fdata['bubbleblur']['enabled']:
                cache_size += fdata['bubbleblur']['bytes']
            if fdata['sprayblur']['enabled']:
                cache_size += fdata['sprayblur']['bytes']
            if 'dustblur' in fdata and fdata['dustblur'][
                    'enabled']:  # If statement to support caches without a dustblur entry
                cache_size += fdata['dustblur']['bytes']
            if fdata['particles']['enabled']:
                cache_size += fdata['particles']['bytes']
            if fdata['obstacle']['enabled']:
                cache_size += fdata['obstacle']['bytes']
        self.cache_bytes.set(cache_size)

    def _update_cache_stats(self):
        dprops = bpy.context.scene.flip_fluid.get_domain_properties()
        if dprops is None:
            return

        cache_directory = dprops.cache.get_cache_abspath()
        statsfile = os.path.join(cache_directory, self.stats_filename)
        if not os.path.isfile(statsfile):
            self.is_frame_info_available = False
            return

        with open(statsfile, 'r') as f:
            cachedata = json.loads(f.read())

        self.is_cache_info_available = True

        is_surface_enabled = False
        is_preview_enabled = False
        is_surfaceblur_enabled = False
        is_foam_enabled = False
        is_bubble_enabled = False
        is_spray_enabled = False
        is_dust_enabled = False
        is_foamblur_enabled = False
        is_bubbleblur_enabled = False
        is_sprayblur_enabled = False
        is_dustblur_enabled = False
        is_particles_enabled = False
        is_obstacle_enabled = False
        surface_bytes = 0
        preview_bytes = 0
        surfaceblur_bytes = 0
        foam_bytes = 0
        bubble_bytes = 0
        spray_bytes = 0
        dust_bytes = 0
        foamblur_bytes = 0
        bubbleblur_bytes = 0
        sprayblur_bytes = 0
        dustblur_bytes = 0
        particles_bytes = 0
        obstacle_bytes = 0

        total_time = 0.0
        time_mesh = 0.0
        time_advection = 0.0
        time_particles = 0.0
        time_pressure = 0.0
        time_diffuse = 0.0
        time_viscosity = 0.0
        time_objects = 0.0
        time_other = 0.0
        is_data_in_cache = False
        num_cache_frames = 0
        for key in cachedata.keys():
            if not key.isdigit():
                continue

            is_data_in_cache = True
            num_cache_frames += 1

            fdata = cachedata[key]
            if fdata['surface']['enabled']:
                is_surface_enabled = True
                surface_bytes += fdata['surface']['bytes']
            if fdata['preview']['enabled']:
                is_preview_enabled = True
                preview_bytes += fdata['preview']['bytes']
            if fdata['surfaceblur']['enabled']:
                is_surfaceblur_enabled = True
                surfaceblur_bytes += fdata['surfaceblur']['bytes']
            if fdata['foam']['enabled']:
                is_foam_enabled = True
                foam_bytes += fdata['foam']['bytes']
            if fdata['bubble']['enabled']:
                is_bubble_enabled = True
                bubble_bytes += fdata['bubble']['bytes']
            if fdata['spray']['enabled']:
                is_spray_enabled = True
                spray_bytes += fdata['spray']['bytes']
            if 'dust' in fdata and fdata['dust'][
                    'enabled']:  # If statement to support caches without a dust entry
                is_dust_enabled = True
                dust_bytes += fdata['dust']['bytes']
            if fdata['foamblur']['enabled']:
                is_foamblur_enabled = True
                foamblur_bytes += fdata['foamblur']['bytes']
            if fdata['bubbleblur']['enabled']:
                is_bubbleeblur_enabled = True
                bubbleblur_bytes += fdata['bubbleblur']['bytes']
            if fdata['sprayblur']['enabled']:
                is_sprayblur_enabled = True
                sprayblur_bytes += fdata['sprayblur']['bytes']
            if 'dustblur' in fdata and fdata['sprayblur'][
                    'enabled']:  # If statement to support caches without a dustblur entry
                is_dustblur_enabled = True
                dustblur_bytes += fdata['dustblur']['bytes']
            if fdata['particles']['enabled']:
                is_particles_enabled = True
                particles_bytes += fdata['particles']['bytes']
            if fdata['obstacle']['enabled']:
                is_obstacle_enabled = True
                obstacle_bytes += fdata['obstacle']['bytes']

            total_time += fdata['timing']['total']
            time_mesh += fdata['timing']['mesh']
            time_advection += fdata['timing']['advection']
            time_particles += fdata['timing']['particles']
            time_pressure += fdata['timing']['pressure']
            time_diffuse += fdata['timing']['diffuse']
            time_viscosity += fdata['timing']['viscosity']
            time_objects += fdata['timing']['objects']

        if not is_data_in_cache:
            self.is_cache_info_available = False
            return

        self.num_cache_frames = num_cache_frames

        self.surface_mesh.enabled = is_surface_enabled
        self.preview_mesh.enabled = is_preview_enabled
        self.surfaceblur_mesh.enabled = is_surfaceblur_enabled
        self.foam_mesh.enabled = is_foam_enabled
        self.bubble_mesh.enabled = is_bubble_enabled
        self.spray_mesh.enabled = is_spray_enabled
        self.dust_mesh.enabled = is_dust_enabled
        self.foamblur_mesh.enabled = is_foamblur_enabled
        self.bubbleblur_mesh.enabled = is_bubbleblur_enabled
        self.sprayblur_mesh.enabled = is_sprayblur_enabled
        self.dustblur_mesh.enabled = is_dustblur_enabled
        self.particle_mesh.enabled = is_particles_enabled
        self.obstacle_mesh.enabled = is_obstacle_enabled

        self.surface_mesh.bytes.set(surface_bytes)
        self.preview_mesh.bytes.set(preview_bytes)
        self.surfaceblur_mesh.bytes.set(surfaceblur_bytes)
        self.foam_mesh.bytes.set(foam_bytes)
        self.bubble_mesh.bytes.set(bubble_bytes)
        self.spray_mesh.bytes.set(spray_bytes)
        self.dust_mesh.bytes.set(dust_bytes)
        self.foamblur_mesh.bytes.set(foamblur_bytes)
        self.bubbleblur_mesh.bytes.set(bubbleblur_bytes)
        self.sprayblur_mesh.bytes.set(sprayblur_bytes)
        self.dustblur_mesh.bytes.set(dustblur_bytes)
        self.particle_mesh.bytes.set(particles_bytes)
        self.obstacle_mesh.bytes.set(obstacle_bytes)

        time_other = (total_time - time_mesh - time_advection -
                      time_particles - time_pressure - time_diffuse -
                      time_viscosity - time_objects)

        self.time_mesh.time = time_mesh
        self.time_advection.time = time_advection
        self.time_particles.time = time_particles
        self.time_pressure.time = time_pressure
        self.time_diffuse.time = time_diffuse
        self.time_viscosity.time = time_viscosity
        self.time_objects.time = time_objects
        self.time_other.time = time_other
        self.display_frame_viscosity_timing_stats = time_viscosity > 0.0
        self.display_frame_diffuse_timing_stats = time_diffuse > 0.0

        self.time_mesh.set_time_pct(100 * time_mesh / total_time)
        self.time_advection.set_time_pct(100 * time_advection / total_time)
        self.time_particles.set_time_pct(100 * time_particles / total_time)
        self.time_pressure.set_time_pct(100 * time_pressure / total_time)
        self.time_diffuse.set_time_pct(100 * time_diffuse / total_time)
        self.time_viscosity.set_time_pct(100 * time_viscosity / total_time)
        self.time_objects.set_time_pct(100 * time_objects / total_time)
        self.time_other.set_time_pct(100 * time_other / total_time)

        frame_speed = self._get_estimated_frame_speed(cachedata)
        self.estimated_frame_speed = frame_speed
        self.is_estimated_time_remaining_available = frame_speed > 0

        if self.is_estimated_time_remaining_available:
            num_frames = dprops.simulation.frame_end - dprops.simulation.frame_start + 1
            frames_left = num_frames - dprops.bake.num_baked_frames
            time_remaining = int(math.ceil((1.0 / frame_speed) * frames_left))
            time_remaining = min(time_remaining, 2147483648 - 1)
            self.estimated_time_remaining = time_remaining
            self.estimated_time_remaining_timestamp = self.get_timestamp()

        self._update_cache_size(cachedata)

    def _get_estimated_frame_speed(self, cachedata):
        max_frame = 0
        num_frames = 0
        total_time = 0.0
        for key in cachedata.keys():
            if not key.isdigit():
                continue
            max_frame = max(max_frame, cachedata[key]['frame'])
            num_frames += 1
            total_time += cachedata[key]['timing']['total']

        if num_frames <= 1:
            return -1.0

        avg_frame_time = total_time / num_frames

        is_frame_data_available = (max_frame + 1) * [False]
        for key in cachedata.keys():
            if not key.isdigit():
                continue
            is_frame_data_available[cachedata[key]['frame']] = True

        frame_times = (max_frame + 1) * [avg_frame_time]
        for key in cachedata.keys():
            if not key.isdigit():
                continue
            frame_times[cachedata[key]
                        ['frame']] = cachedata[key]['timing']['total']

        # First frame is often innaccurate, so discard
        frame_times.pop(0)

        frame_speeds = []
        for t in frame_times:
            frame_speeds.append(1.0 / max(1e-6, t))

        smoothing_factor = 0.1
        average_speed = frame_speeds[0]
        for s in frame_speeds:
            average_speed = smoothing_factor * s + (
                1.0 - smoothing_factor) * average_speed
        return average_speed
Example #17
0
class NamedLayer(PropertyGroup):
    name = StringProperty(name="Layer Name")
    use_lock = BoolProperty(name="Lock Layer", default=False)
    use_object_select = BoolProperty(name="Object Select", default=True)
    use_wire = BoolProperty(name="Wire Layer", default=False)
Example #18
0
class IMPORT_OT_image_to_plane(Operator, AddObjectHelper):
    """Create mesh plane(s) from image files with the appropiate aspect ratio"""
    bl_idname = "import_image.to_plane"
    bl_label = "Import Images as Planes"
    bl_options = {'REGISTER', 'UNDO'}

    # -----------
    # File props.
    files = CollectionProperty(type=bpy.types.OperatorFileListElement,
                               options={'HIDDEN', 'SKIP_SAVE'})

    directory = StringProperty(maxlen=1024,
                               subtype='FILE_PATH',
                               options={'HIDDEN', 'SKIP_SAVE'})

    # Show only images/videos, and directories!
    filter_image = BoolProperty(default=True, options={'HIDDEN', 'SKIP_SAVE'})
    filter_movie = BoolProperty(default=True, options={'HIDDEN', 'SKIP_SAVE'})
    filter_folder = BoolProperty(default=True, options={'HIDDEN', 'SKIP_SAVE'})
    filter_glob = StringProperty(default="", options={'HIDDEN', 'SKIP_SAVE'})

    # --------
    # Options.
    align = BoolProperty(name="Align Planes",
                         default=True,
                         description="Create Planes in a row")

    align_offset = FloatProperty(name="Offset",
                                 min=0,
                                 soft_min=0,
                                 default=0.1,
                                 description="Space between Planes")

    # Callback which will update File window's filter options accordingly to extension setting.
    def update_extensions(self, context):
        is_cycles = context.scene.render.engine == 'CYCLES'
        if self.extension == DEFAULT_EXT:
            self.filter_image = True
            # XXX Hack to avoid allowing videos with Cycles, crashes currently!
            self.filter_movie = True and not is_cycles
            self.filter_glob = ""
        else:
            self.filter_image = False
            self.filter_movie = False
            if is_cycles:
                # XXX Hack to avoid allowing videos with Cycles!
                flt = ";".join(("*." + e for e in EXT_FILTER[self.extension][0]
                                if e not in VID_EXT_FILTER))
            else:
                flt = ";".join(
                    ("*." + e for e in EXT_FILTER[self.extension][0]))
            self.filter_glob = flt
        # And now update space (file select window), if possible.
        space = bpy.context.space_data
        # XXX Can't use direct op comparison, these are not the same objects!
        if (space.type != 'FILE_BROWSER'
                or space.operator.bl_rna.identifier != self.bl_rna.identifier):
            return
        space.params.use_filter_image = self.filter_image
        space.params.use_filter_movie = self.filter_movie
        space.params.filter_glob = self.filter_glob
        # XXX Seems to be necessary, else not all changes above take effect...
        bpy.ops.file.refresh()

    extension = EnumProperty(name="Extension",
                             items=gen_ext_filter_ui_items(),
                             description="Only import files of this type",
                             update=update_extensions)

    # -------------------
    # Plane size options.
    _size_modes = (
        ('ABSOLUTE', "Absolute", "Use absolute size"),
        ('DPI', "Dpi", "Use definition of the image as dots per inch"),
        ('DPBU', "Dots/BU",
         "Use definition of the image as dots per Blender Unit"),
    )
    size_mode = EnumProperty(
        name="Size Mode",
        default='ABSOLUTE',
        items=_size_modes,
        description="How the size of the plane is computed")

    height = FloatProperty(name="Height",
                           description="Height of the created plane",
                           default=1.0,
                           min=0.001,
                           soft_min=0.001,
                           subtype='DISTANCE',
                           unit='LENGTH')

    factor = FloatProperty(
        name="Definition",
        min=1.0,
        default=600.0,
        description="Number of pixels per inch or Blender Unit")

    # -------------------------
    # Blender material options.
    t = bpy.types.Material.bl_rna.properties["use_shadeless"]
    use_shadeless = BoolProperty(name=t.name,
                                 default=False,
                                 description=t.description)

    use_transparency = BoolProperty(
        name="Use Alpha",
        default=False,
        description="Use alphachannel for transparency")

    t = bpy.types.Material.bl_rna.properties["transparency_method"]
    items = tuple(
        (it.identifier, it.name, it.description) for it in t.enum_items)
    transparency_method = EnumProperty(name="Transp. Method",
                                       description=t.description,
                                       items=items)

    t = bpy.types.Material.bl_rna.properties["use_transparent_shadows"]
    use_transparent_shadows = BoolProperty(name=t.name,
                                           default=False,
                                           description=t.description)

    #-------------------------
    # Cycles material options.
    shader = EnumProperty(name="Shader",
                          items=CYCLES_SHADERS,
                          description="Node shader to use")

    overwrite_node_tree = BoolProperty(
        name="Overwrite Material",
        default=True,
        description="Overwrite existing Material with new nodetree "
        "(based on material name)")

    # --------------
    # Image Options.
    t = bpy.types.Image.bl_rna.properties["alpha_mode"]
    alpha_mode_items = tuple(
        (e.identifier, e.name, e.description) for e in t.enum_items)
    alpha_mode = EnumProperty(name=t.name,
                              items=alpha_mode_items,
                              default=t.default,
                              description=t.description)

    t = bpy.types.IMAGE_OT_match_movie_length.bl_rna
    match_len = BoolProperty(name=t.name,
                             default=True,
                             description=t.description)

    t = bpy.types.Image.bl_rna.properties["use_fields"]
    use_fields = BoolProperty(name=t.name,
                              default=False,
                              description=t.description)

    t = bpy.types.ImageUser.bl_rna.properties["use_auto_refresh"]
    use_auto_refresh = BoolProperty(name=t.name,
                                    default=True,
                                    description=t.description)

    relative = BoolProperty(name="Relative",
                            default=True,
                            description="Apply relative paths")

    def draw(self, context):
        engine = context.scene.render.engine
        layout = self.layout

        box = layout.box()
        box.label("Import Options:", icon='FILTER')
        box.prop(self, "extension", icon='FILE_IMAGE')
        box.prop(self, "align")
        box.prop(self, "align_offset")

        row = box.row()
        row.active = bpy.data.is_saved
        row.prop(self, "relative")
        # XXX Hack to avoid allowing videos with Cycles, crashes currently!
        if engine == 'BLENDER_RENDER':
            box.prop(self, "match_len")
            box.prop(self, "use_fields")
            box.prop(self, "use_auto_refresh")

        box = layout.box()
        if engine == 'BLENDER_RENDER':
            box.label("Material Settings: (Blender)", icon='MATERIAL')
            box.prop(self, "use_shadeless")
            box.prop(self, "use_transparency")
            box.prop(self, "alpha_mode")
            row = box.row()
            row.prop(self, "transparency_method", expand=True)
            box.prop(self, "use_transparent_shadows")
        elif engine == 'CYCLES':
            box = layout.box()
            box.label("Material Settings: (Cycles)", icon='MATERIAL')
            box.prop(self, 'shader', expand=True)
            box.prop(self, 'overwrite_node_tree')

        box = layout.box()
        box.label("Plane dimensions:", icon='ARROW_LEFTRIGHT')
        row = box.row()
        row.prop(self, "size_mode", expand=True)
        if self.size_mode == 'ABSOLUTE':
            box.prop(self, "height")
        else:
            box.prop(self, "factor")

    def invoke(self, context, event):
        self.update_extensions(context)
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}

    def execute(self, context):
        if not bpy.data.is_saved:
            self.relative = False

        # the add utils don't work in this case because many objects are added disable relevant things beforehand
        editmode = context.user_preferences.edit.use_enter_edit_mode
        context.user_preferences.edit.use_enter_edit_mode = False
        if context.active_object and context.active_object.mode == 'EDIT':
            bpy.ops.object.mode_set(mode='OBJECT')

        self.import_images(context)

        context.user_preferences.edit.use_enter_edit_mode = editmode
        return {'FINISHED'}

    # Main...
    def import_images(self, context):
        engine = context.scene.render.engine
        import_list, directory = self.generate_paths()

        images = (load_image(path, directory) for path in import_list)

        if engine in {'BLENDER_RENDER', 'BLENDER_GAME'}:
            textures = []
            for img in images:
                self.set_image_options(img)
                textures.append(self.create_image_textures(context, img))

            materials = (self.create_material_for_texture(tex)
                         for tex in textures)
        elif engine == 'CYCLES':
            materials = (self.create_cycles_material(img) for img in images)
        else:
            return

        planes = tuple(
            self.create_image_plane(context, mat) for mat in materials)

        context.scene.update()
        if self.align:
            self.align_planes(planes)

        for plane in planes:
            plane.select = True

        self.report({'INFO'}, "Added {} Image Plane(s)".format(len(planes)))

    def create_image_plane(self, context, material):
        engine = context.scene.render.engine
        if engine in {'BLENDER_RENDER', 'BLENDER_GAME'}:
            img = material.texture_slots[0].texture.image
        elif engine == 'CYCLES':
            nodes = material.node_tree.nodes
            img = next(
                (node.image for node in nodes if node.type == 'TEX_IMAGE'))
        px, py = img.size

        # can't load data
        if px == 0 or py == 0:
            px = py = 1

        if self.size_mode == 'ABSOLUTE':
            y = self.height
            x = px / py * y
        elif self.size_mode == 'DPI':
            fact = 1 / self.factor / context.scene.unit_settings.scale_length * 0.0254
            x = px * fact
            y = py * fact
        else:  # elif self.size_mode == 'DPBU'
            fact = 1 / self.factor
            x = px * fact
            y = py * fact

        bpy.ops.mesh.primitive_plane_add('INVOKE_REGION_WIN')
        plane = context.scene.objects.active
        # Why does mesh.primitive_plane_add leave the object in edit mode???
        if plane.mode is not 'OBJECT':
            bpy.ops.object.mode_set(mode='OBJECT')
        plane.dimensions = x, y, 0.0
        plane.name = material.name
        bpy.ops.object.transform_apply(scale=True)
        plane.data.uv_textures.new()
        plane.data.materials.append(material)
        plane.data.uv_textures[0].data[0].image = img

        material.game_settings.use_backface_culling = False
        material.game_settings.alpha_blend = 'ALPHA'
        return plane

    def align_planes(self, planes):
        gap = self.align_offset
        offset = 0
        for i, plane in enumerate(planes):
            offset += (plane.dimensions.x / 2.0) + gap
            if i == 0:
                continue
            move_local = mathutils.Vector((offset, 0.0, 0.0))
            move_world = plane.location + move_local * plane.matrix_world.inverted(
            )
            plane.location += move_world
            offset += (plane.dimensions.x / 2.0)

    def generate_paths(self):
        return (fn.name for fn in self.files
                if is_image_fn(fn.name, self.extension)), self.directory

    # Internal
    def create_image_textures(self, context, image):
        fn_full = os.path.normpath(bpy.path.abspath(image.filepath))

        # look for texture with importsettings
        for texture in bpy.data.textures:
            if texture.type == 'IMAGE':
                tex_img = texture.image
                if (tex_img is not None) and (tex_img.library is None):
                    fn_tex_full = os.path.normpath(
                        bpy.path.abspath(tex_img.filepath))
                    if fn_full == fn_tex_full:
                        self.set_texture_options(context, texture)
                        return texture

        # if no texture is found: create one
        name_compat = bpy.path.display_name_from_filepath(image.filepath)
        texture = bpy.data.textures.new(name=name_compat, type='IMAGE')
        texture.image = image
        self.set_texture_options(context, texture)
        return texture

    def create_material_for_texture(self, texture):
        # look for material with the needed texture
        for material in bpy.data.materials:
            slot = material.texture_slots[0]
            if slot and slot.texture == texture:
                self.set_material_options(material, slot)
                return material

        # if no material found: create one
        name_compat = bpy.path.display_name_from_filepath(
            texture.image.filepath)
        material = bpy.data.materials.new(name=name_compat)
        slot = material.texture_slots.add()
        slot.texture = texture
        slot.texture_coords = 'UV'
        self.set_material_options(material, slot)
        return material

    def set_image_options(self, image):
        image.alpha_mode = self.alpha_mode
        image.use_fields = self.use_fields

        if self.relative:
            try:  # can't always find the relative path (between drive letters on windows)
                image.filepath = bpy.path.relpath(image.filepath)
            except ValueError:
                pass

    def set_texture_options(self, context, texture):
        texture.image.use_alpha = self.use_transparency
        texture.image_user.use_auto_refresh = self.use_auto_refresh
        if self.match_len:
            ctx = context.copy()
            ctx["edit_image"] = texture.image
            ctx["edit_image_user"] = texture.image_user
            bpy.ops.image.match_movie_length(ctx)

    def set_material_options(self, material, slot):
        if self.use_transparency:
            material.alpha = 0.0
            material.specular_alpha = 0.0
            slot.use_map_alpha = True
        else:
            material.alpha = 1.0
            material.specular_alpha = 1.0
            slot.use_map_alpha = False
        material.use_transparency = self.use_transparency
        material.transparency_method = self.transparency_method
        material.use_shadeless = self.use_shadeless
        material.use_transparent_shadows = self.use_transparent_shadows

    #--------------------------------------------------------------------------
    # Cycles
    def create_cycles_material(self, image):
        name_compat = bpy.path.display_name_from_filepath(image.filepath)
        material = None
        for mat in bpy.data.materials:
            if mat.name == name_compat and self.overwrite_node_tree:
                material = mat
        if not material:
            material = bpy.data.materials.new(name=name_compat)

        material.use_nodes = True
        node_tree = material.node_tree
        out_node = clean_node_tree(node_tree)

        if self.shader == 'BSDF_DIFFUSE':
            bsdf_diffuse = node_tree.nodes.new('ShaderNodeBsdfDiffuse')
            tex_image = node_tree.nodes.new('ShaderNodeTexImage')
            tex_image.image = image
            tex_image.show_texture = True
            node_tree.links.new(out_node.inputs[0], bsdf_diffuse.outputs[0])
            node_tree.links.new(bsdf_diffuse.inputs[0], tex_image.outputs[0])

        elif self.shader == 'EMISSION':
            emission = node_tree.nodes.new('ShaderNodeEmission')
            lightpath = node_tree.nodes.new('ShaderNodeLightPath')
            tex_image = node_tree.nodes.new('ShaderNodeTexImage')
            tex_image.image = image
            tex_image.show_texture = True
            node_tree.links.new(out_node.inputs[0], emission.outputs[0])
            node_tree.links.new(emission.inputs[0], tex_image.outputs[0])
            node_tree.links.new(emission.inputs[1], lightpath.outputs[0])

        elif self.shader == 'BSDF_DIFFUSE_BSDF_TRANSPARENT':
            bsdf_diffuse = node_tree.nodes.new('ShaderNodeBsdfDiffuse')
            bsdf_transparent = node_tree.nodes.new('ShaderNodeBsdfTransparent')
            mix_shader = node_tree.nodes.new('ShaderNodeMixShader')
            tex_image = node_tree.nodes.new('ShaderNodeTexImage')
            tex_image.image = image
            tex_image.show_texture = True
            node_tree.links.new(out_node.inputs[0], mix_shader.outputs[0])
            node_tree.links.new(mix_shader.inputs[0], tex_image.outputs[1])
            node_tree.links.new(mix_shader.inputs[2], bsdf_diffuse.outputs[0])
            node_tree.links.new(mix_shader.inputs[1],
                                bsdf_transparent.outputs[0])
            node_tree.links.new(bsdf_diffuse.inputs[0], tex_image.outputs[0])

        elif self.shader == 'EMISSION_BSDF_TRANSPARENT':
            emission = node_tree.nodes.new('ShaderNodeEmission')
            lightpath = node_tree.nodes.new('ShaderNodeLightPath')
            bsdf_transparent = node_tree.nodes.new('ShaderNodeBsdfTransparent')
            mix_shader = node_tree.nodes.new('ShaderNodeMixShader')
            tex_image = node_tree.nodes.new('ShaderNodeTexImage')
            tex_image.image = image
            tex_image.show_texture = True
            node_tree.links.new(out_node.inputs[0], mix_shader.outputs[0])
            node_tree.links.new(mix_shader.inputs[0], tex_image.outputs[1])
            node_tree.links.new(mix_shader.inputs[2], emission.outputs[0])
            node_tree.links.new(mix_shader.inputs[1],
                                bsdf_transparent.outputs[0])
            node_tree.links.new(emission.inputs[0], tex_image.outputs[0])
            node_tree.links.new(emission.inputs[1], lightpath.outputs[0])

        auto_align_nodes(node_tree)
        return material
Example #19
0
class SvProfileNodeMK2(bpy.types.Node, SverchCustomTreeNode):
    '''
    Triggers: svg-like 2d profiles
    Tooltip: Generate multiple parameteric 2d profiles using SVG like syntax

    SvProfileNode generates one or more profiles / elevation segments using;
    assignments, variables, and a string descriptor similar to SVG.

    This node expects simple input, or vectorized input.
    - sockets with no input are automatically 0, not None
    - The longest input array will be used to extend the shorter ones, using last value repeat.
    '''

    bl_idname = 'SvProfileNodeMK2'
    bl_label = 'Profile Parametric'
    bl_icon = 'SYNTAX_ON'

    replacement_nodes = [('SvProfileNodeMK3', None, None)]
    SvLists: bpy.props.CollectionProperty(type=SvListGroup)
    SvSubLists: bpy.props.CollectionProperty(type=SvSublistGroup)

    def mode_change(self, context):
        if not (self.selected_axis == self.current_axis):
            self.label = self.selected_axis
            self.current_axis = self.selected_axis
            updateNode(self, context)

    x: BoolProperty(default=True)
    y: BoolProperty(default=True)

    axis_options = [("X", "X", "", 0), ("Y", "Y", "", 1), ("Z", "Z", "", 2)]

    current_axis: StringProperty(default='Z')

    knotsnames: StringProperty(name='knotsnames', default='')
    selected_axis: EnumProperty(
        items=axis_options,
        update=mode_change,
        name="Type of axis",
        description="offers basic axis output vectors X|Y|Z",
        default="Z")

    profile_file: StringProperty(default="", update=updateNode)
    filename: StringProperty(default="", update=updateNode)
    posxy: FloatVectorProperty(default=(0.0, 0.0), size=2)
    extended_parsing: BoolProperty(default=False)

    precision: IntProperty(
        name="Precision",
        min=0,
        max=10,
        default=8,
        update=updateNode,
        description=
        "decimal precision of coordinates when generating profile from selection"
    )

    curve_points_count: IntProperty(
        name="Curve points count",
        min=1,
        max=100,
        default=20,
        update=updateNode,
        description="Default number of points on curve segment")

    def draw_buttons(self, context, layout):
        col = layout.column(align=True)
        row = col.row()
        do_text = row.operator('node.sverchok_profilizer',
                               text='from selection')
        do_text.nodename = self.name
        do_text.treename = self.id_data.name
        do_text.x = self.x
        do_text.y = self.y
        row = col.row()
        row.prop(self, 'selected_axis', expand=True)
        row = col.row(align=True)
        # row.prop(self, "profile_file", text="")
        row.prop_search(self,
                        'filename',
                        bpy.data,
                        'texts',
                        text='',
                        icon='TEXT')

    def draw_buttons_ext(self, context, layout):
        row = layout.row(align=True)
        row.prop(self, "extended_parsing", text="extended parsing")
        layout.label(text="Profile Generator settings")
        layout.prop(self, "precision")
        layout.prop(self, "curve_points_count")
        row = layout.row(align=True)
        row.prop(self, "x", text='x-affect', expand=True)
        row.prop(self, "y", text='y-affect', expand=True)

    def sv_init(self, context):
        self.inputs.new('SvStringsSocket', "a")
        self.inputs.new('SvStringsSocket', "b")

        self.outputs.new('SvVerticesSocket', "Verts")
        self.outputs.new('SvStringsSocket', "Edges")
        self.outputs.new('SvVerticesSocket', "Knots")
        self.outputs.new('SvStringsSocket', "KnotsNames")

    def adjust_inputs(self):
        '''
        takes care of adding new inputs until reaching 26,
        '''
        inputs = self.inputs
        if inputs[-1].is_linked:
            new_index = len(inputs)
            new_letter = idx_map.get(new_index, None)
            if new_letter:
                inputs.new('SvStringsSocket', new_letter, new_letter)
            else:
                print(
                    'this implementation goes up to 26 chars only, use SN or EK'
                )
                print('- or contact Dealga')
        elif not inputs[-2].is_linked:
            inputs.remove(inputs[-1])

    def sv_update(self):
        '''
        update analyzes the state of the node and returns if the criteria to start processing
        are not met.
        '''

        # keeping the file internal for now.
        if not (self.filename in bpy.data.texts):
            return

        if not ('KnotsNames' in self.outputs):
            return

        elif len([1 for inputs in self.inputs if inputs.is_linked]) == 0:
            ''' must have at least one input... '''
            return

        self.adjust_inputs()

    def homogenize_input(self, segments, longest):
        '''
        edit segments in place, extend all to match length of longest
        '''
        for letter, letter_dict in segments.items():
            if letter_dict['length'] < longest:
                fullList(letter_dict['data'], longest)

    def meta_get(self, s_name, fallback, level):
        '''
        private function for the get_input function, accepts level 0..2
        - if socket has no links, then return fallback value
        - s_name can be an index instead of socket name
        '''
        inputs = self.inputs
        if inputs[s_name].is_linked:
            socket_in = inputs[s_name].sv_get()
            if level == 1:
                data = dataCorrect(socket_in)[0]
            elif level == 2:
                data = dataCorrect(socket_in)[0][0]
            else:
                data = dataCorrect(socket_in)
            return data
        else:
            return fallback

    def get_input(self):
        '''
        collect all input socket data, and track the longest sequence.
        '''
        segments = {}
        longest = 0
        for i, input_ in enumerate(self.inputs):
            letter = idx_map[i]
            ''' get socket data, or use a fallback '''
            data = self.meta_get(i, [0], 2)

            num_datapoints = len(data)
            segments[letter] = {'length': num_datapoints, 'data': data}

            if num_datapoints > longest:
                longest = num_datapoints

        return segments, longest

    def process(self):

        if not self.outputs[0].is_linked:
            return

        segments, longest = self.get_input()

        if longest < 1:
            print('logic error, longest < 1')
            return

        self.homogenize_input(segments, longest)
        full_result_verts = []
        full_result_edges = []

        for idx in range(longest):
            path_object = PathParser(self, segments, idx)
            vertices, edges = path_object.get_geometry()

            axis_fill = {
                'X': lambda coords: (0, coords[0], coords[1]),
                'Y': lambda coords: (coords[0], 0, coords[1]),
                'Z': lambda coords: (coords[0], coords[1], 0)
            }.get(self.current_axis)

            vertices = list(map(axis_fill, vertices))
            full_result_verts.append(vertices)
            full_result_edges.append(edges)

        if full_result_verts:
            outputs = self.outputs
            outputs['Verts'].sv_set(full_result_verts)

            if outputs['Edges'].is_linked:
                outputs['Edges'].sv_set(full_result_edges)
        try:
            knots = []
            for knot in self.SvLists['knots'].SvSubLists:
                knots.append([knot.SvX, knot.SvY, knot.SvZ])
            #print('test',knots)
            outputs[2].sv_set([knots])
        except:
            outputs[2].sv_set([])
        try:
            names = []
            for i, knot in enumerate(self.SvLists['knotsnames'].SvSubLists):
                names.append([knot.SvName])
            outputs[3].sv_set([names])
        except:
            outputs[3].sv_set([])

    def storage_set_data(self, storage):

        self.id_data.freeze(hard=True)
        self.SvLists.clear()

        strings_json = storage['profile_sublist_storage']

        out_points = json.loads(strings_json)['knots']
        self.SvLists.add().name = 'knots'
        for k in out_points:
            item = self.SvLists['knots'].SvSubLists.add()
            item.SvX, item.SvY, item.SvZ = k

        out_names = json.loads(strings_json)['knotsnames']
        self.SvLists.add().name = 'knotsnames'
        for k in out_names:
            item = self.SvLists['knotsnames'].SvSubLists.add()
            item.SvName = k

        self.id_data.unfreeze(hard=True)

    def storage_get_data(self, node_dict):
        local_storage = {'knots': [], 'knotsnames': []}

        if "knots" in self.SvLists:
            # implies "knotsnames" will be found too.. because that's how it works..
            for knot in self.SvLists['knots'].SvSubLists:
                local_storage['knots'].append([knot.SvX, knot.SvY, knot.SvZ])

            for outname in self.SvLists['knotsnames'].SvSubLists:
                local_storage['knotsnames'].append(outname.SvName)

        # store anyway
        node_dict['profile_sublist_storage'] = json.dumps(local_storage,
                                                          sort_keys=True)

        if self.filename:
            node_dict['path_file'] = bpy.data.texts[self.filename].as_string()
        else:
            node_dict['path_file'] = ""
Example #20
0
class UI_OT_i18n_addon_translation_import(Operator):
    """Import given add-on's translation data from PO files"""
    bl_idname = "ui.i18n_addon_translation_import"
    bl_label = "I18n Add-on Import"

    # Operator Arguments
    module_name: EnumProperty(
        name="Add-on",
        description="Add-on to process",
        options=set(),
        items=enum_addons,
    )

    directory: StringProperty(subtype='FILE_PATH',
                              maxlen=1024,
                              options={'HIDDEN', 'SKIP_SAVE'})

    # /End Operator Arguments

    def _dst(self, trans, path, uid, kind):
        if kind == 'PO':
            if uid == self.settings.PARSER_TEMPLATE_ID:
                return os.path.join(self.directory, "blender.pot")
            path = os.path.join(self.directory, uid)
            if os.path.isdir(path):
                return os.path.join(path, uid + ".po")
            return path + ".po"
        elif kind == 'PY':
            return trans._dst(trans, path, uid, kind)
        return path

    def invoke(self, context, event):
        global _cached_enum_addons
        _cached_enum_addons[:] = []
        if not hasattr(self, "settings"):
            self.settings = settings.settings
        module_name, mod = validate_module(self, context)
        if mod:
            self.directory = os.path.dirname(mod.__file__)
            self.module_name = module_name
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}

    def execute(self, context):
        global _cached_enum_addons
        _cached_enum_addons[:] = []
        if not hasattr(self, "settings"):
            self.settings = settings.settings
        i18n_sett = context.window_manager.i18n_update_svn_settings

        module_name, mod = validate_module(self, context)
        if not (module_name and mod):
            return {'CANCELLED'}

        path = mod.__file__
        if path.endswith("__init__.py"):
            path = os.path.dirname(path)

        trans = utils_i18n.I18n(kind='PY', src=path, settings=self.settings)

        # Now search given dir, to find po's matching given languages...
        # Mapping po_uid: po_file.
        po_files = dict(utils_i18n.get_po_files_from_dir(self.directory))

        # Note: uids in i18n_sett.langs and addon's py code should be the same (both taken from the locale's languages
        #       file). So we just try to find the best match in po's for each enabled uid.
        for lng in i18n_sett.langs:
            if lng.uid in self.settings.IMPORT_LANGUAGES_SKIP:
                print(
                    "Skipping {} language ({}), edit settings if you want to enable it."
                    .format(lng.name, lng.uid))
                continue
            if not lng.use:
                print("Skipping {} language ({}).".format(lng.name, lng.uid))
                continue
            uid = lng.uid
            po_uid = utils_i18n.find_best_isocode_matches(uid, po_files.keys())
            if not po_uid:
                print("Skipping {} language, no PO file found for it ({}).".
                      format(lng.name, uid))
                continue
            po_uid = po_uid[0]
            msgs = utils_i18n.I18nMessages(uid=uid,
                                           kind='PO',
                                           key=uid,
                                           src=po_files[po_uid],
                                           settings=self.settings)
            if uid in trans.trans:
                trans.trans[uid].merge(msgs, replace=True)
            else:
                trans.trans[uid] = msgs

        trans.write(kind='PY')

        return {'FINISHED'}
Example #21
0
def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

    # Define properties
    Scene.measureit_default_color = FloatVectorProperty(
        name="Default color",
        description="Default Color",
        default=(0.173, 0.545, 1.0, 1.0),
        min=0.1,
        max=1,
        subtype='COLOR',
        size=4)
    Scene.measureit_font_size = IntProperty(name="Text Size",
                                            description="Default text size",
                                            default=14, min=10, max=150)
    Scene.measureit_hint_space = FloatProperty(name='Separation', min=0, max=100, default=0.1,
                                               precision=3,
                                               description="Default distance to display measure")
    Scene.measureit_gl_ghost = BoolProperty(name="All",
                                            description="Display measures for all objects,"
                                                        " not only selected",
                                            default=True)
    Scene.measureit_gl_txt = StringProperty(name="Text", maxlen=256,
                                            description="Short description (use | for line break)")

    Scene.measureit_gl_precision = IntProperty(name='Precision', min=0, max=5, default=2,
                                               description="Number of decimal precision")
    Scene.measureit_gl_show_d = BoolProperty(name="ShowDist",
                                             description="Display distances",
                                             default=True)
    Scene.measureit_gl_show_n = BoolProperty(name="ShowName",
                                             description="Display texts",
                                             default=False)
    Scene.measureit_scale = BoolProperty(name="Scale",
                                         description="Use scale factor",
                                         default=False)
    Scene.measureit_scale_factor = FloatProperty(name='Factor', min=0.001, max=9999999,
                                                 default=1.0,
                                                 precision=3,
                                                 description="Scale factor 1:x")
    Scene.measureit_scale_color = FloatVectorProperty(name="Scale color",
                                                      description="Scale Color",
                                                      default=(1, 1, 0, 1.0),
                                                      min=0.1,
                                                      max=1,
                                                      subtype='COLOR',
                                                      size=4)
    Scene.measureit_scale_font = IntProperty(name="Font",
                                             description="Text size",
                                             default=14, min=10, max=150)
    Scene.measureit_scale_pos_x = IntProperty(name="X Position",
                                              description="Margin on the X axis",
                                              default=5,
                                              min=0,
                                              max=100)
    Scene.measureit_scale_pos_y = IntProperty(name="Y Position",
                                              description="Margin on the Y axis",
                                              default=5,
                                              min=0,
                                              max=100)
    Scene.measureit_gl_scaletxt = StringProperty(name="ScaleText", maxlen=48,
                                                 description="Scale title",
                                                 default="Scale:")
    Scene.measureit_scale_precision = IntProperty(name='Precision', min=0, max=5, default=0,
                                                  description="Number of decimal precision")
    Scene.measureit_ovr = BoolProperty(name="Override",
                                       description="Override colors and fonts",
                                       default=False)
    Scene.measureit_ovr_font = IntProperty(name="Font",
                                           description="Override text size",
                                           default=14, min=10, max=150)
    Scene.measureit_ovr_color = FloatVectorProperty(name="Override color",
                                                    description="Override Color",
                                                    default=(1, 0, 0, 1.0),
                                                    min=0.1,
                                                    max=1,
                                                    subtype='COLOR',
                                                    size=4)
    Scene.measureit_ovr_width = IntProperty(name='Override width', min=1, max=10, default=1,
                                            description='override line width')

    Scene.measureit_ovr_font_rotation = IntProperty(name='Rotate', min=0, max=360, default=0,
                                                    description="Text rotation in degrees")
    Scene.measureit_ovr_font_align = EnumProperty(items=(('L', "Left Align", "Use current render"),
                                                         ('C', "Center Align", ""),
                                                         ('R', "Right Align", "")),
                                                  name="Align Font",
                                                  description="Set Font Alignment")
    Scene.measureit_units = EnumProperty(items=(('1', "Automatic", "Use scene units"),
                                                ('2', "Meters", ""),
                                                ('3', "Centimeters", ""),
                                                ('4', "Millimeters", ""),
                                                ('5', "Feet", ""),
                                                ('6', "Inches", "")),
                                         name="Units",
                                         default="2",
                                         description="Units")
    Scene.measureit_hide_units = BoolProperty(name="hide_units",
                                              description="Do not display unit of measurement on viewport",
                                              default=False)
    Scene.measureit_render = BoolProperty(name="Render",
                                          description="Save an image with measures over"
                                                      " render image",
                                          default=False)
    Scene.measureit_render_type = EnumProperty(items=(('1', "Frame", "Render current frame"),
                                                      ('2', "Animation", "")),
                                               name="Render type",
                                               description="Type of render image")
    Scene.measureit_sum = EnumProperty(items=(('99', "-", "Select a group for sum"),
                                              ('0', "A", ""),
                                              ('1', "B", ""),
                                              ('2', "C", ""),
                                              ('3', "D", ""),
                                              ('4', "E", ""),
                                              ('5', "F", ""),
                                              ('6', "G", ""),
                                              ('7', "H", ""),
                                              ('8', "I", ""),
                                              ('9', "J", ""),
                                              ('10', "K", ""),
                                              ('11', "L", ""),
                                              ('12', "M", ""),
                                              ('13', "N", ""),
                                              ('14', "O", ""),
                                              ('15', "P", ""),
                                              ('16', "Q", ""),
                                              ('17', "R", ""),
                                              ('18', "S", ""),
                                              ('19', "T", ""),
                                              ('20', "U", ""),
                                              ('21', "V", ""),
                                              ('22', "W", ""),
                                              ('23', "X", ""),
                                              ('24', "Y", ""),
                                              ('25', "Z", "")),
                                       name="Sum in Group",
                                       description="Add segment length in selected group")

    Scene.measureit_rf = BoolProperty(name="render_frame",
                                      description="Add a frame in render output",
                                      default=False)
    Scene.measureit_rf_color = FloatVectorProperty(name="Fcolor",
                                                   description="Frame Color",
                                                   default=(0.9, 0.9, 0.9, 1.0),
                                                   min=0.1,
                                                   max=1,
                                                   subtype='COLOR',
                                                   size=4)
    Scene.measureit_rf_border = IntProperty(name='fborder ', min=1, max=1000, default=10,
                                            description='Frame space from border')
    Scene.measureit_rf_line = IntProperty(name='fline', min=1, max=10, default=1,
                                          description='Line width for border')

    Scene.measureit_glarrow_a = EnumProperty(items=(('99', "--", "No arrow"),
                                                    ('1', "Line",
                                                     "The point of the arrow are lines"),
                                                    ('2', "Triangle",
                                                     "The point of the arrow is triangle"),
                                                    ('3', "TShape",
                                                     "The point of the arrow is a T")),
                                             name="A end",
                                             description="Add arrows to point A")
    Scene.measureit_glarrow_b = EnumProperty(items=(('99', "--", "No arrow"),
                                                    ('1', "Line",
                                                     "The point of the arrow are lines"),
                                                    ('2', "Triangle",
                                                     "The point of the arrow is triangle"),
                                                    ('3', "TShape",
                                                     "The point of the arrow is a T")),
                                             name="B end",
                                             description="Add arrows to point B")
    Scene.measureit_glarrow_s = IntProperty(name="Size",
                                            description="Arrow size",
                                            default=15, min=6, max=500)

    Scene.measureit_debug = BoolProperty(name="Debug",
                                         description="Display information for debugging"
                                                     " (expand/collapse for enabling or disabling)"
                                                     " this information is only renderered for "
                                                     "selected objects",
                                         default=False)
    Scene.measureit_debug_select = BoolProperty(name="Selected",
                                                description="Display information "
                                                            "only for selected items",
                                                default=False)
    Scene.measureit_debug_vertices = BoolProperty(name="Vertices",
                                                  description="Display vertex index number",
                                                  default=True)
    Scene.measureit_debug_objects = BoolProperty(name="Objects",
                                                 description="Display object scene index number",
                                                 default=False)
    Scene.measureit_debug_vert_loc = BoolProperty(name="Location",
                                                  description="Display vertex location",
                                                  default=False)
    Scene.measureit_debug_object_loc = BoolProperty(name="Location",
                                                    description="Display object location",
                                                    default=False)
    Scene.measureit_debug_edges = BoolProperty(name="Edges",
                                               description="Display edge index number",
                                               default=False)
    Scene.measureit_debug_faces = BoolProperty(name="Faces",
                                               description="Display face index number",
                                               default=False)
    Scene.measureit_debug_normals = BoolProperty(name="Normals",
                                                 description="Display face normal "
                                                             "vector and creation order",
                                                 default=False)
    Scene.measureit_debug_normal_details = BoolProperty(name="Details",
                                                        description="Display face normal details",
                                                        default=True)
    Scene.measureit_debug_font = IntProperty(name="Font",
                                             description="Debug text size",
                                             default=14, min=10, max=150)
    Scene.measureit_debug_vert_color = FloatVectorProperty(name="Debug color",
                                                           description="Debug Color",
                                                           default=(1, 0, 0, 1.0),
                                                           min=0.1,
                                                           max=1,
                                                           subtype='COLOR',
                                                           size=4)
    Scene.measureit_debug_face_color = FloatVectorProperty(name="Debug face color",
                                                           description="Debug face Color",
                                                           default=(0, 1, 0, 1.0),
                                                           min=0.1,
                                                           max=1,
                                                           subtype='COLOR',
                                                           size=4)
    Scene.measureit_debug_norm_color = FloatVectorProperty(name="Debug vector color",
                                                           description="Debug vector Color",
                                                           default=(1.0, 1.0, 0.1, 1.0),
                                                           min=0.1,
                                                           max=1,
                                                           subtype='COLOR',
                                                           size=4)
    Scene.measureit_debug_edge_color = FloatVectorProperty(name="Debug vector color",
                                                           description="Debug vector Color",
                                                           default=(0.1, 1.0, 1.0, 1.0),
                                                           min=0.1,
                                                           max=1,
                                                           subtype='COLOR',
                                                           size=4)
    Scene.measureit_debug_obj_color = FloatVectorProperty(name="Debug vector color",
                                                          description="Debug vector Color",
                                                          default=(1.0, 1.0, 1.0, 1.0),
                                                          min=0.1,
                                                          max=1,
                                                          subtype='COLOR',
                                                          size=4)
    Scene.measureit_debug_normal_size = FloatProperty(name='Len', min=0.001, max=9,
                                                      default=0.5,
                                                      precision=2,
                                                      description="Normal arrow size")
    Scene.measureit_debug_width = IntProperty(name='Debug width', min=1, max=10, default=2,
                                              description='Vector line thickness')
    Scene.measureit_debug_precision = IntProperty(name='Precision', min=0, max=5, default=1,
                                                  description="Number of decimal precision")
    Scene.measureit_debug_vert_loc_toggle = EnumProperty(items=(('1', "Local",
                                                                 "Uses local coordinates"),
                                                                ('2', "Global",
                                                                 "Uses global coordinates")),
                                                         name="Coordinates",
                                                         description="Choose coordinate system")
    Scene.measureit_font_rotation = IntProperty(name='Rotate', min=0, max=360, default=0,
                                                description="Default text rotation in degrees")
    Scene.measureit_font_align = EnumProperty(items=(('L', "Left Align", "Use current render"),
                                                     ('C', "Center Align", ""),
                                                     ('R', "Right Align", "")),
                                              name="Align Font",
                                              description="Set Font Alignment")

    # OpenGL flag
    wm = WindowManager
    # register internal property
    wm.measureit_run_opengl = BoolProperty(default=False)
Example #22
0
class UI_OT_i18n_addon_translation_export(Operator):
    """Export given add-on's translation data as PO files"""

    bl_idname = "ui.i18n_addon_translation_export"
    bl_label = "I18n Add-on Export"

    # Operator Arguments
    module_name: EnumProperty(name="Add-on",
                              description="Add-on to process",
                              items=enum_addons,
                              options=set())

    use_export_pot: BoolProperty(
        name="Export POT",
        description="Export (generate) a POT file too",
        default=True,
    )

    use_update_existing: BoolProperty(
        name="Update Existing",
        description=
        "Update existing po files, if any, instead of overwriting them",
        default=True,
    )

    directory: StringProperty(subtype='FILE_PATH',
                              maxlen=1024,
                              options={'HIDDEN', 'SKIP_SAVE'})

    # /End Operator Arguments

    def _dst(self, trans, path, uid, kind):
        if kind == 'PO':
            if uid == self.settings.PARSER_TEMPLATE_ID:
                return os.path.join(self.directory, "blender.pot")
            path = os.path.join(self.directory, uid)
            if os.path.isdir(path):
                return os.path.join(path, uid + ".po")
            return path + ".po"
        elif kind == 'PY':
            return trans._dst(trans, path, uid, kind)
        return path

    def invoke(self, context, event):
        global _cached_enum_addons
        _cached_enum_addons[:] = []
        if not hasattr(self, "settings"):
            self.settings = settings.settings
        module_name, mod = validate_module(self, context)
        if mod:
            self.directory = os.path.dirname(mod.__file__)
            self.module_name = module_name
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}

    def execute(self, context):
        global _cached_enum_addons
        _cached_enum_addons[:] = []
        if not hasattr(self, "settings"):
            self.settings = settings.settings
        i18n_sett = context.window_manager.i18n_update_svn_settings

        module_name, mod = validate_module(self, context)
        if not (module_name and mod):
            return {'CANCELLED'}

        path = mod.__file__
        if path.endswith("__init__.py"):
            path = os.path.dirname(path)

        trans = utils_i18n.I18n(kind='PY', src=path, settings=self.settings)
        trans.dst = self._dst

        uids = [self.settings.PARSER_TEMPLATE_ID
                ] if self.use_export_pot else []
        for lng in i18n_sett.langs:
            if lng.uid in self.settings.IMPORT_LANGUAGES_SKIP:
                print(
                    "Skipping {} language ({}), edit settings if you want to enable it."
                    .format(lng.name, lng.uid))
                continue
            if not lng.use:
                print("Skipping {} language ({}).".format(lng.name, lng.uid))
                continue
            uid = utils_i18n.find_best_isocode_matches(lng.uid,
                                                       trans.trans.keys())
            if uid:
                uids.append(uid[0])

        # Try to update existing POs instead of overwriting them, if asked to do so!
        if self.use_update_existing:
            for uid in uids:
                if uid == self.settings.PARSER_TEMPLATE_ID:
                    continue
                path = trans.dst(trans, trans.src[uid], uid, 'PO')
                if not os.path.isfile(path):
                    continue
                msgs = utils_i18n.I18nMessages(kind='PO',
                                               src=path,
                                               settings=self.settings)
                msgs.update(trans.msgs[self.settings.PARSER_TEMPLATE_ID])
                trans.msgs[uid] = msgs

        trans.write(kind='PO', langs=set(uids))

        return {'FINISHED'}
Example #23
0
def init_props():
    w_mgr = bpy.types.WindowManager
    w_mgr.skin_prop = EnumProperty(
        name="skin",
        description="Skin Adjust",
        items=[
            ('1', 'Base Color.Hue', '1'),
            ('2', 'Base Color.Saturation', '2'),
            ('3', 'Base Color.Value', '3'),
            ('4', 'Base Color.Bright', '4'),
            ('5', 'Base Color.Contrast', '5'),
            ('6', 'Specular', '6'),
            ('7', 'Roughness', '7'),
            ('8', 'Roughness.Contrast', '8'),
            ('9', 'Specular.Contrast', '9'),
            ('10', 'Subsurface.Scale', '10'),
            ('11', 'Normal.Strength', '11'),
            ('12', 'Bump.Strength', '12'),
            ('13', 'Bump.Distance', '13'),
            ('14', 'Displacement.Height', '14'),
        ],
        default='1',
    )
    w_mgr.eye_prop = EnumProperty(
        name="skin",
        description="Eyes Adjust",
        items=[
            ('1', 'Base Color.Hue', '1'),
            ('2', 'Base Color.Saturation', '2'),
            ('3', 'Base Color.Value', '3'),
            ('4', 'Base Color.Bright', '4'),
            ('5', 'Base Color.Contrast', '5'),
            ('6', 'Normal.Strength', '6'),
            ('7', 'Bump.Strength', '7'),
            ('8', 'Bump.Distance', '8'),
        ],
        default='1',
    )
    w_mgr.search_prop = StringProperty(name="",
                                       default="",
                                       description="Search_shape_keys",
                                       update=DtbCommands.search_morph_)
    w_mgr.is_eye = BoolProperty(name="eyes")
    w_mgr.ftime_prop = BoolProperty(name="ftime")
    w_mgr.br_onoff_prop = BoolProperty(name="br_onoff",
                                       default=True,
                                       update=DtbIKBones.bonerange_onoff)
    w_mgr.ifk0 = BoolProperty(name="ifk0",
                              default=False,
                              update=DtbIKBones.ifk_update0)
    w_mgr.ifk1 = BoolProperty(name="ifk1",
                              default=False,
                              update=DtbIKBones.ifk_update1)
    w_mgr.ifk2 = BoolProperty(name="ifk2",
                              default=False,
                              update=DtbIKBones.ifk_update2)
    w_mgr.ifk3 = BoolProperty(name="fik3",
                              default=False,
                              update=DtbIKBones.ifk_update3)
    w_mgr.new_morph = BoolProperty(name="_new_morph", default=False)
    w_mgr.skip_isk = BoolProperty(name="_skip_isk", default=False)
    w_mgr.update_viewport = BoolProperty(
        name="update_viewport",
        description=
        "Updates the Viewport, Scene Settings, and Camera for your Scale",
        default=True)
    w_mgr.quick_heavy = BoolProperty(name="quick_heavy", default=False)
    w_mgr.combine_materials = BoolProperty(name="combine_materials",
                                           default=True)
    w_mgr.add_pose_lib = BoolProperty(name="add_pose_lib", default=True)
    figure_items = [("null", "Choose Character",
                     "Select which figure you wish to import")]
    w_mgr.choose_daz_figure = EnumProperty(
        name="Highlight for Collection",
        description=
        "Choose any figure in your scene to which you wish to add a pose.",
        items=figure_items,
        default="null",
    )
    w_mgr.scene_scale = EnumProperty(
        name="Scene Scale",
        description=
        "Used to change scale of imported object and scale settings",
        items=[('0.01', 'Real Scale (Centimeters)', 'Daz Scale'),
               ('0.1', 'x10', '10 x Daz Scale'),
               ('1', 'x100 (Meters)', '100 x Daz Scale')],
        default='0.01')
    w_mgr.search_morph_list = StringProperty(
        name="",
        default="Type Keyword Here",
        description="Search_shape_keys",
    )
class MUV_OT_PreserveUVAspect(bpy.types.Operator):
    """
    Operation class: Preserve UV Aspect
    """

    bl_idname = "uv.muv_preserve_uv_aspect"
    bl_label = "Preserve UV Aspect"
    bl_description = "Choose Image"
    bl_options = {'REGISTER', 'UNDO'}

    dest_img_name = StringProperty(options={'HIDDEN'})
    origin = EnumProperty(name="Origin",
                          description="Aspect Origin",
                          items=[
                              ('CENTER', 'Center', 'Center'),
                              ('LEFT_TOP', 'Left Top', 'Left Bottom'),
                              ('LEFT_CENTER', 'Left Center', 'Left Center'),
                              ('LEFT_BOTTOM', 'Left Bottom', 'Left Bottom'),
                              ('CENTER_TOP', 'Center Top', 'Center Top'),
                              ('CENTER_BOTTOM', 'Center Bottom',
                               'Center Bottom'),
                              ('RIGHT_TOP', 'Right Top', 'Right Top'),
                              ('RIGHT_CENTER', 'Right Center', 'Right Center'),
                              ('RIGHT_BOTTOM', 'Right Bottom', 'Right Bottom')
                          ],
                          default="CENTER")

    @classmethod
    def poll(cls, context):
        # we can not get area/space/region from console
        if common.is_console_mode():
            return True
        return _is_valid_context(context)

    def execute(self, context):
        # Note: the current system only works if the
        # f[tex_layer].image doesn't return None
        # which will happen in certain cases
        objs = common.get_uv_editable_objects(context)

        obj_list = {}  # { Material: Object }
        for obj in objs:
            if common.check_version(2, 80, 0) >= 0:
                # If more than two selected objects shares same
                # material, we need to calculate new UV coordinates
                # before image on texture node is overwritten.
                material_to_rewrite = []
                for slot in obj.material_slots:
                    if not slot.material:
                        continue
                    nodes = common.find_texture_nodes_from_material(
                        slot.material)
                    if len(nodes) >= 2:
                        self.report(
                            {'WARNING'}, "Object {} must not have more than 2 "
                            "shader nodes with image texture".format(obj.name))
                        return {'CANCELLED'}
                    if not nodes:
                        continue
                    material_to_rewrite.append(slot.material)

                if len(material_to_rewrite) >= 2:
                    self.report(
                        {'WARNING'}, "Object {} must not have more than 2 "
                        "materials with image texture".format(obj.name))
                    return {'CANCELLED'}
                if len(material_to_rewrite) == 0:
                    self.report({'WARNING'},
                                "Object {} must not have more than 1 "
                                "material with image texture".format(obj.name))
                    return {'CANCELLED'}
                if material_to_rewrite[0] not in obj_list.keys():
                    obj_list[material_to_rewrite[0]] = []
                obj_list[material_to_rewrite[0]].append(obj)
            else:
                # If blender version is < (2, 79), multiple objects editing
                # mode is not supported. So, we add dummy key to obj_list.
                obj_list["Dummy"] = [obj]

        # pylint: disable=R1702
        for mtrl, o in obj_list.items():
            for obj in o:
                bm = bmesh.from_edit_mesh(obj.data)

                if common.check_version(2, 73, 0) >= 0:
                    bm.faces.ensure_lookup_table()

                if not bm.loops.layers.uv:
                    self.report({'WARNING'},
                                "Object must have more than one UV map")
                    return {'CANCELLED'}

                uv_layer = bm.loops.layers.uv.verify()

                sel_faces = [f for f in bm.faces if f.select]
                dest_img = bpy.data.images[self.dest_img_name]

                info = {}

                if compat.check_version(2, 80, 0) >= 0:
                    tex_image = common.find_image(obj)
                    for f in sel_faces:
                        if tex_image not in info.keys():
                            info[tex_image] = {}
                            info[tex_image]['faces'] = []
                        info[tex_image]['faces'].append(f)
                else:
                    tex_layer = bm.faces.layers.tex.verify()
                    for f in sel_faces:
                        if not f[tex_layer].image in info.keys():
                            info[f[tex_layer].image] = {}
                            info[f[tex_layer].image]['faces'] = []
                        info[f[tex_layer].image]['faces'].append(f)

                for img in info:
                    if img is None:
                        continue

                    src_img = img
                    ratio = Vector((dest_img.size[0] / src_img.size[0],
                                    dest_img.size[1] / src_img.size[1]))

                    if self.origin == 'CENTER':
                        origin = Vector((0.0, 0.0))
                        num = 0
                        for f in info[img]['faces']:
                            for l in f.loops:
                                uv = l[uv_layer].uv
                                origin = origin + uv
                                num = num + 1
                        origin = origin / num
                    elif self.origin == 'LEFT_TOP':
                        origin = Vector((100000.0, -100000.0))
                        for f in info[img]['faces']:
                            for l in f.loops:
                                uv = l[uv_layer].uv
                                origin.x = min(origin.x, uv.x)
                                origin.y = max(origin.y, uv.y)
                    elif self.origin == 'LEFT_CENTER':
                        origin = Vector((100000.0, 0.0))
                        num = 0
                        for f in info[img]['faces']:
                            for l in f.loops:
                                uv = l[uv_layer].uv
                                origin.x = min(origin.x, uv.x)
                                origin.y = origin.y + uv.y
                                num = num + 1
                        origin.y = origin.y / num
                    elif self.origin == 'LEFT_BOTTOM':
                        origin = Vector((100000.0, 100000.0))
                        for f in info[img]['faces']:
                            for l in f.loops:
                                uv = l[uv_layer].uv
                                origin.x = min(origin.x, uv.x)
                                origin.y = min(origin.y, uv.y)
                    elif self.origin == 'CENTER_TOP':
                        origin = Vector((0.0, -100000.0))
                        num = 0
                        for f in info[img]['faces']:
                            for l in f.loops:
                                uv = l[uv_layer].uv
                                origin.x = origin.x + uv.x
                                origin.y = max(origin.y, uv.y)
                                num = num + 1
                        origin.x = origin.x / num
                    elif self.origin == 'CENTER_BOTTOM':
                        origin = Vector((0.0, 100000.0))
                        num = 0
                        for f in info[img]['faces']:
                            for l in f.loops:
                                uv = l[uv_layer].uv
                                origin.x = origin.x + uv.x
                                origin.y = min(origin.y, uv.y)
                                num = num + 1
                        origin.x = origin.x / num
                    elif self.origin == 'RIGHT_TOP':
                        origin = Vector((-100000.0, -100000.0))
                        for f in info[img]['faces']:
                            for l in f.loops:
                                uv = l[uv_layer].uv
                                origin.x = max(origin.x, uv.x)
                                origin.y = max(origin.y, uv.y)
                    elif self.origin == 'RIGHT_CENTER':
                        origin = Vector((-100000.0, 0.0))
                        num = 0
                        for f in info[img]['faces']:
                            for l in f.loops:
                                uv = l[uv_layer].uv
                                origin.x = max(origin.x, uv.x)
                                origin.y = origin.y + uv.y
                                num = num + 1
                        origin.y = origin.y / num
                    elif self.origin == 'RIGHT_BOTTOM':
                        origin = Vector((-100000.0, 100000.0))
                        for f in info[img]['faces']:
                            for l in f.loops:
                                uv = l[uv_layer].uv
                                origin.x = max(origin.x, uv.x)
                                origin.y = min(origin.y, uv.y)
                    else:
                        self.report({'ERROR'}, "Unknown Operation")
                        return {'CANCELLED'}

                    info[img]['ratio'] = ratio
                    info[img]['origin'] = origin

                for img in info:
                    if img is None:
                        continue

                    for f in info[img]['faces']:
                        if compat.check_version(2, 80, 0) < 0:
                            tex_layer = bm.faces.layers.tex.verify()
                            f[tex_layer].image = dest_img
                        for l in f.loops:
                            uv = l[uv_layer].uv
                            origin = info[img]['origin']
                            ratio = info[img]['ratio']
                            diff = uv - origin
                            diff.x = diff.x / ratio.x
                            diff.y = diff.y / ratio.y
                            uv.x = origin.x + diff.x
                            uv.y = origin.y + diff.y
                            l[uv_layer].uv = uv

                bmesh.update_edit_mesh(obj.data)

            if compat.check_version(2, 80, 0) >= 0:
                nodes = common.find_texture_nodes_from_material(mtrl)
                nodes[0].image = dest_img

        return {'FINISHED'}
Example #25
0
class SvGroupNode(bpy.types.Node, SverchCustomTreeNode, StoreSockets):
    '''
    Sverchok Group node
    '''
    bl_idname = 'SvGroupNode'
    bl_label = 'Group'
    bl_icon = 'OUTLINER_OB_EMPTY'

    group_name = StringProperty()

    def update(self):
        '''
        Override inherited
        '''
        pass

    def draw_buttons(self, context, layout):
        if self.id_data.bl_idname == "SverchCustomTreeType":
            op = layout.operator("node.sv_node_group_edit")
            op.group_name = self.group_name

    def adjust_sockets(self, nodes):
        swap = {"inputs": "outputs", "outputs": "inputs"}
        for n in nodes:
            data = ast.literal_eval(n.socket_data)
            """
            This below is somewhat broken and needs
            to be reworked.
            """

            print("adjusting sockets", data)
            for k, values in data.items():
                sockets = getattr(self, swap[k])
                for i, socket_data in enumerate(values):
                    if len(socket_data) == 3 and socket_data[2]:
                        print(socket_data)
                        s_type, s_name, s_old_name = socket_data
                        curr_socket = sockets[s_old_name]
                        print(curr_socket.name)
                        s = curr_socket.replace_socket(s_type, s_name, i)
                        print(s.name)
                    else:
                        sockets.new(*socket_data)

    def process(self):
        group_ng = bpy.data.node_groups[self.group_name]
        in_node = find_node("SvGroupInputsNode", group_ng)
        out_node = find_node('SvGroupOutputsNode', group_ng)
        for socket in self.inputs:
            if socket.is_linked:
                data = socket.sv_get(deepcopy=False)
                in_node.outputs[socket.name].sv_set(data)
        #  get update list
        #  could be cached
        ul = make_tree_from_nodes([out_node.name], group_ng, down=False)
        do_update(ul, group_ng.nodes)
        # set output sockets correctly
        for socket in self.outputs:
            if socket.is_linked:
                data = out_node.inputs[socket.name].sv_get(deepcopy=False)
                socket.sv_set(data)

    def load(self):
        data = ast.literal_eval(self.socket_data)
        for k, values in data.items():
            sockets = getattr(self, k)
            sockets.clear()
            for s in values:
                if not s[1] in sockets:
                    sockets.new(*s)

    def get_sockets(self):
        yield self.inputs, "inputs"
        yield self.outputs, "outputs"
Example #26
0
class SvListSplitNode(bpy.types.Node, SverchCustomTreeNode):
    ''' List Split '''
    bl_idname = 'SvListSplitNode'
    bl_label = 'List Split'
    bl_icon = 'OUTLINER_OB_EMPTY'

    def change_mode(self, context):
        if self.unwrap:
            self.level_unwrap = max(1, self.level)
        else:
            self.level = self.level_unwrap
        updateNode(self, context)

    level = IntProperty(name='Level', default=1, min=0, update=updateNode)
    level_unwrap = IntProperty(name='Level',
                               default=1,
                               min=1,
                               update=updateNode)
    split = IntProperty(name='Split size', default=1, min=1, update=updateNode)
    unwrap = BoolProperty(name='Unwrap', default=True, update=change_mode)

    typ = StringProperty(name='typ', default='')
    newsock = BoolProperty(name='newsock', default=False)

    def draw_buttons(self, context, layout):
        if self.unwrap:
            layout.prop(self, "level_unwrap", text="level")
        else:
            layout.prop(self, "level", text="level")
        layout.prop(self, "unwrap")

    def sv_init(self, context):
        self.inputs.new('StringsSocket', "Data")
        self.inputs.new('StringsSocket', "Split").prop_name = 'split'
        self.outputs.new('StringsSocket', "Split")

    def update(self):
        if 'Data' in self.inputs and self.inputs['Data'].links:
            inputsocketname = 'Data'
            outputsocketname = ['Split']
            changable_sockets(self, inputsocketname, outputsocketname)

    def process(self):
        if 'Split' in self.outputs and self.outputs['Split'].is_linked:
            if 'Data' in self.inputs and self.inputs['Data'].is_linked:
                data = self.inputs['Data'].sv_get()
                sizes = self.inputs['Split'].sv_get()[0]
                if self.unwrap:
                    out = self.get(data, self.level_unwrap, sizes)
                elif self.level:
                    out = self.get(data, self.level, sizes)
                else:
                    out = split(data, sizes[0])
                self.outputs['Split'].sv_set(out)

    def get(self, data, level, size):
        if not isinstance(data, (list, tuple)):
            return data
        if not isinstance(data[0], (list, tuple)):
            return data
        if level > 1:  # find level to work on
            return [self.get(d, level - 1, size) for d in data]
        elif level == 1:  # execute the chosen function
            sizes = repeat_last(size)
            if self.unwrap:
                return list(
                    chain.from_iterable((split(d, next(sizes)) for d in data)))
            else:
                return [split(d, next(sizes)) for d in data]
        else:  # Fail
            return None
Example #27
0
class LuxCoreConfigPhotonGI(PropertyGroup):
    enabled: BoolProperty(
        name=
        "Use PhotonGI cache to accelerate indirect and/or caustic light rendering",
        default=False)

    # Shared settings
    photon_maxcount: FloatProperty(
        name="Photon Count (Millions)",
        default=20,
        min=1,
        soft_max=100,
        precision=0,
        step=10,
        description="Max. number of photons traced (value in millions)")
    photon_maxdepth: IntProperty(
        name="Photon Depth",
        default=8,
        min=3,
        max=64,
        description=
        "Max. depth of photon paths. At each bounce, a photon might be stored")
    # I use 0.049 as default because then glossy materials with default roughness (0.05) are cached
    glossinessusagethreshold: FloatProperty(
        name="Glossiness Threshold",
        default=0.049,
        min=0,
        max=1,
        description=PHOTONGI_GLOSSINESSTHRESH_DESC)

    # Indirect cache
    indirect_enabled: BoolProperty(
        name="Use Indirect Cache",
        default=True,
        description="Accelerates rendering of indirect light")
    indirect_haltthreshold_preset_items = [
        ("final", "Final Render", "Halt Threshold 5%", 0),
        ("preview", "Preview", "Halt Threshold 15%", 1),
        ("custom", "Custom", "", 2),
    ]
    indirect_haltthreshold_preset: EnumProperty(
        name="Quality",
        items=indirect_haltthreshold_preset_items,
        default="final",
        description=PHOTONGI_HALTTHRESH_DESC)
    indirect_haltthreshold_custom: FloatProperty(
        name="Halt Threshold",
        default=5,
        min=0.001,
        max=100,
        precision=0,
        subtype="PERCENTAGE",
        description=PHOTONGI_HALTTHRESH_DESC)
    indirect_lookup_radius_auto: BoolProperty(
        name="Automatic Lookup Radius",
        default=True,
        description="Automatically choose a good lookup radius")
    indirect_lookup_radius: FloatProperty(name="Lookup Radius",
                                          default=0.15,
                                          min=0.00001,
                                          subtype="DISTANCE",
                                          description=LOOKUP_RADIUS_DESC)
    indirect_normalangle: FloatProperty(name="Normal Angle",
                                        default=radians(10),
                                        min=0,
                                        max=radians(90),
                                        subtype="ANGLE",
                                        description=NORMAL_ANGLE_DESC)
    indirect_usagethresholdscale: FloatProperty(
        name="Brute Force Radius Scale",
        default=8,
        min=0,
        precision=1,
        description=PHOTONGI_INDIRECT_USAGETHRESHOLDSCALE_DESC)

    # Caustic cache
    caustic_enabled: BoolProperty(
        name="Use Caustic Cache",
        default=False,
        description=
        "Accelerates rendering of caustics at the cost of blurring them")
    caustic_maxsize: FloatProperty(
        name="Max. Size (Millions)",
        default=0.1,
        soft_min=0.01,
        min=0.001,
        soft_max=10,
        precision=1,
        step=1,
        description=
        "Max. number of photons stored in caustic cache (value in millions)")
    caustic_lookup_radius: FloatProperty(name="Lookup Radius",
                                         default=0.075,
                                         min=0.00001,
                                         subtype="DISTANCE",
                                         description=LOOKUP_RADIUS_DESC)
    caustic_normalangle: FloatProperty(name="Normal Angle",
                                       default=radians(10),
                                       min=0,
                                       max=radians(90),
                                       subtype="ANGLE",
                                       description=NORMAL_ANGLE_DESC)
    caustic_periodic_update: BoolProperty(
        name="Periodic Update",
        default=True,
        description=
        "Rebuild the caustic cache periodically to clean up photon noise. "
        "The step samples parameter controls how often the cache is rebuilt")
    caustic_updatespp: IntProperty(
        name="Step Samples",
        default=8,
        min=1,
        description=
        "How often to rebuild the cache if periodic update is enabled")
    caustic_updatespp_radiusreduction: FloatProperty(
        name="Radius Reduction",
        default=96,
        min=1,
        soft_min=70,
        max=99.9,
        soft_max=99,
        subtype="PERCENTAGE",
        description="Shrinking factor for the lookup radius after each pass")
    caustic_updatespp_minradius: FloatProperty(
        name="Minimum Radius",
        default=0.003,
        min=0.00001,
        subtype="DISTANCE",
        description="Radius at which the radius reduction stops")

    debug_items = [
        ("off", "Off (Final Render Mode)", "", 0),
        ("showindirect", "Show Indirect", "View the indirect light cache", 1),
        ("showindirectpathmix", "Show Indirect/Path Mix",
         "Blue = cache is used, red = brute force path tracing is used", 3),
        ("showcaustic", "Show Caustic", "View the caustic cache", 2),
    ]
    debug: EnumProperty(
        name="Debug",
        items=debug_items,
        default="off",
        description=
        "Choose between final render mode or a debug representation of the caches"
    )

    file_path: StringProperty(
        name="File Path",
        subtype="FILE_PATH",
        description="File path to the PhotonGI cache file")
    save_or_overwrite: BoolProperty(
        name="",
        default=False,
        description=
        "Save the cache to a file or overwrite the existing cache file. "
        "If you want to use the saved cache, disable this option")
Example #28
0
class CarverPrefs(bpy.types.AddonPreferences):
    bl_idname = __name__

    Enable_Tab_01: BoolProperty(
        name="Info",
        description="Some general information and settings about the add-on",
        default=False)
    Enable_Tab_02: BoolProperty(
        name="Hotkeys",
        description="List of the shortcuts used during carving",
        default=False)
    bpy.types.Scene.Key_Create: StringProperty(name="Object creation",
                                               description="Object creation",
                                               maxlen=1,
                                               default="C")
    bpy.types.Scene.Key_Update: StringProperty(
        name="Auto Bevel Update",
        description="Auto Bevel Update",
        maxlen=1,
        default="A",
    )
    bpy.types.Scene.Key_Bool: StringProperty(
        name="Boolean type",
        description="Boolean operation type",
        maxlen=1,
        default="T",
    )
    bpy.types.Scene.Key_Brush: StringProperty(
        name="Brush Mode",
        description="Brush Mode",
        maxlen=1,
        default="B",
    )
    bpy.types.Scene.Key_Help: StringProperty(
        name="Help display",
        description="Help display",
        maxlen=1,
        default="H",
    )
    bpy.types.Scene.Key_Instant: StringProperty(
        name="Instantiate",
        description="Instantiate object",
        maxlen=1,
        default="I",
    )
    bpy.types.Scene.Key_Close: StringProperty(
        name="Close polygonal shape",
        description="Close polygonal shape",
        maxlen=1,
        default="X",
    )
    bpy.types.Scene.Key_Apply: StringProperty(
        name="Apply operation",
        description="Apply operation",
        maxlen=1,
        default="Q",
    )
    bpy.types.Scene.Key_Scale: StringProperty(
        name="Scale object",
        description="Scale object",
        maxlen=1,
        default="S",
    )
    bpy.types.Scene.Key_Gapy: StringProperty(
        name="Gap rows",
        description="Scale gap between columns",
        maxlen=1,
        default="J",
    )
    bpy.types.Scene.Key_Gapx: StringProperty(
        name="Gap columns",
        description="Scale gap between columns",
        maxlen=1,
        default="U",
    )
    bpy.types.Scene.Key_Depth: StringProperty(
        name="Depth",
        description="Cursor depth or solidify pattern",
        maxlen=1,
        default="D",
    )
    bpy.types.Scene.Key_BrushDepth: StringProperty(
        name="Brush Depth",
        description="Brush depth",
        maxlen=1,
        default="C",
    )
    bpy.types.Scene.Key_Subadd: StringProperty(
        name="Add subdivision",
        description="Add subdivision",
        maxlen=1,
        default="X",
    )
    bpy.types.Scene.Key_Subrem: StringProperty(
        name="Remove subdivision",
        description="Remove subdivision",
        maxlen=1,
        default="W",
    )
    bpy.types.Scene.Key_Randrot: StringProperty(
        name="Random rotation",
        description="Random rotation",
        maxlen=1,
        default="R",
    )
    bpy.types.Scene.ProfilePrefix: StringProperty(
        name="Profile prefix",
        description="Prefix to look for profiles with",
        default="Carver_Profile-")

    def draw(self, context):
        scene = context.scene
        layout = self.layout
        print("DRAW !")

        icon_1 = "TRIA_RIGHT" if not self.Enable_Tab_01 else "TRIA_DOWN"
        box = layout.box()

        box.prop(self,
                 "Enable_Tab_01",
                 text="Info and Settings",
                 emboss=False,
                 icon=icon_1)
        if self.Enable_Tab_01:
            box.label(text="Carver Operator:", icon="LAYER_ACTIVE")
            box.label(
                text=
                "Select a Mesh Object and press [CTRL]+[SHIFT]+[X] to carve",
                icon="LAYER_USED")
            box.label(text="To finish carving press [ESC] or [RIGHT CLICK]",
                      icon="LAYER_USED")
            box.prop(scene, "ProfilePrefix", text="Profile prefix")

        icon_2 = "TRIA_RIGHT" if not self.Enable_Tab_02 else "TRIA_DOWN"
        box = layout.box()
        box.prop(self, "Enable_Tab_02", text="Keys", emboss=False, icon=icon_2)
        if self.Enable_Tab_02:
            split = box.split(align=True)
            box = split.box()
            col = box.column(align=True)
            col.label(text="Object Creation:")
            col.prop(scene, "Key_Create", text="")
            col.label(text="Auto bevel update:")
            col.prop(scene, "Key_Update", text="")
            col.label(text="Boolean operation type:")
            col.prop(scene, "Key_Bool", text="")
            col.label(text="Brush Depth:")
            col.prop(scene, "Key_BrushDepth", text="")

            box = split.box()
            col = box.column(align=True)
            col.label(text="Brush Mode:")
            col.prop(scene, "Key_Brush", text="")
            col.label(text="Help display:")
            col.prop(scene, "Key_Help", text="")
            col.label(text="Instantiate object:")
            col.prop(scene, "Key_Instant", text="")
            col.label(text="Random rotation:")
            col.prop(scene, "Key_Randrot", text="")

            box = split.box()
            col = box.column(align=True)
            col.label(text="Close polygonal shape:")
            col.prop(scene, "Key_Close", text="")
            col.label(text="Apply operation:")
            col.prop(scene, "Key_Apply", text="")
            col.label(text="Scale object:")
            col.prop(scene, "Key_Scale", text="")
            col.label(text="Subdiv add:")
            col.prop(scene, "Key_Subadd", text="")

            box = split.box()
            col = box.column(align=True)
            col.label(text="Gap rows:")
            col.prop(scene, "Key_Gapy", text="")
            col.label(text="Gap columns:")
            col.prop(scene, "Key_Gapx", text="")
            col.label(text="Depth / Solidify:")
            col.prop(scene, "Key_Depth", text="")
            col.label(text="Subdiv Remove:")
            col.prop(scene, "Key_Subrem", text="")
Example #29
0
class CloudRigProperties(bpy.types.PropertyGroup):
    options: BoolProperty(name="CloudRig Settings",
                          description="Show CloudRig Settings",
                          default=False)
    create_root: BoolProperty(name="Create Root",
                              description="Create the root control",
                              default=True)
    double_root: BoolProperty(name="Double Root",
                              description="Create two root controls",
                              default=False)
    custom_script: StringProperty(
        name="Custom Script",
        description="Execute a python script after the rig is generated")
    mechanism_movable: BoolProperty(
        name="Movable Helpers",
        description="Whether helper bones can be moved or not",
        default=True)
    mechanism_selectable: BoolProperty(
        name="Selectable Helpers",
        description="Whether helper bones can be selected or not",
        default=True)
    properties_bone: BoolProperty(
        name="Properties Bone",
        description=
        "Specify a bone to store Properties on. This bone doesn't have to exist in the metarig",
        default=True)

    prefix_separator: EnumProperty(
        name="Prefix Separator",
        description="Character that separates prefixes in the bone names",
        items=separators,
        default="-")
    suffix_separator: EnumProperty(
        name="Suffix Separator",
        description="Character that separates suffixes in the bone names",
        items=separators,
        default=".")

    override_options: BoolProperty(
        name="Override Bone Layers",
        description=
        "Instead of allowing rig elements to assign deform/mechanism/org bone layers individually, set it from the generator instead.",
        default=False)

    root_bone_group: StringProperty(
        name="Root",
        description="Bone Group to assign the root bone to",
        default="Root")
    root_layers: BoolVectorProperty(
        size=32,
        subtype='LAYER',
        description="Layers to assign the root bone to",
        default=[l == 0 for l in range(32)])

    root_parent_group: StringProperty(
        name="Root Parent",
        description="Bone Group to assign the second root bone to",
        default="Root Parent")
    root_parent_layers: BoolVectorProperty(
        size=32,
        subtype='LAYER',
        description="Layers to assign the the second root bone to",
        default=[l == 0 for l in range(32)])

    override_def_layers: BoolProperty(
        name="Deform",
        description=
        "Instead of allowing rig elements to assign deform layers individually, set it from the generator instead",
        default=True)
    def_layers: BoolVectorProperty(
        size=32,
        subtype='LAYER',
        description=
        "Select what layers this set of bones should be assigned to",
        default=[l == 29 for l in range(32)])

    override_mch_layers: BoolProperty(
        name="Mechanism",
        description=
        "Instead of allowing rig elements to assign mechanism layers individually, set it from the generator instead",
        default=True)
    mch_layers: BoolVectorProperty(
        size=32,
        subtype='LAYER',
        description=
        "Select what layers this set of bones should be assigned to",
        default=[l == 30 for l in range(32)])

    override_org_layers: BoolProperty(
        name="Original",
        description=
        "Instead of allowing rig elements to assign original bones' layers individually, set it from the generator instead",
        default=True)
    org_layers: BoolVectorProperty(
        size=32,
        subtype='LAYER',
        description=
        "Select what layers this set of bones should be assigned to",
        default=[l == 31 for l in range(32)])
Example #30
0
class GGT_OT_INIT_CHARACTER_OT_GGT(bpy.types.Operator, ImportHelper):
    """Initializes imported model for the tool"""
    bl_idname = "wm_ggt.init_character"
    bl_label = "Initialize Character"
    bl_description = "Used to init 'Main' Armature. Loaded character should have 'T-Pose' animation from Mixamo."
    bl_options = {'REGISTER', 'UNDO'}
    filename_ext = ".fbx"
    filter_glob = StringProperty(default="*.fbx", options={'HIDDEN'})
    files = CollectionProperty(type=bpy.types.PropertyGroup)
    supported_extensions = ['fbx']

    def import_from_folder(self, file_path, context):
        extension = (os.path.splitext(file_path)[1])[1:].lower()

        if os.path.isdir(file_path):
            return (
                'ERROR',
                'Please select a file containing the T-Pose of your character.'
            )
        elif extension not in self.supported_extensions:
            return (
                'ERROR',
                'The extension of the selected file is not supported. Must be one of the following: '
                + ','.join(self.supported_extensions))
        elif hasattr(bpy.types, bpy.ops.import_scene.fbx.idname()):
            bpy.ops.import_scene.fbx(filepath=file_path)
            return ('INFO', 'Import successful')

    def execute(self, context):
        scene = context.scene
        tool = scene.godot_game_tools
        armature_key = "main_armature"
        self.report({'INFO'}, 'Loading Character T-Pose')
        filePathWithName = bpy.path.abspath(self.properties.filepath)
        import_result = self.import_from_folder(filePathWithName, context)
        if import_result[0] != 'INFO':
            self.report({import_result[0]}, import_result[1])
            return {'CANCELLED'}

        characterArmature = bpy.context.view_layer.objects.active
        if characterArmature != None or characterArmature.type in ["ARMATURE"]:
            bpy.data.objects[
                characterArmature.name][armature_key] = armature_key
            if len(characterArmature.children) > 0:
                for mesh in characterArmature.children:
                    bpy.data.objects[mesh.name][armature_key] = armature_key

            tool.rootmotion_hip_bone = "Hips" if "Hips" in [
                bone.name.replace('mixamorig:', '')
                for bone in characterArmature.data.bones
            ] else ""
            characterArmature.name = "Armature"

            # Remove Cleared Keyframe Actions - Mixamo Fix
            for action in bpy.data.actions:
                if len(action.fcurves) == 0: bpy.data.actions.remove(action)

            if len(bpy.data.actions) > 0:
                tool.target_object = characterArmature
                characterArmature[armature_key] = armature_key
                for action in bpy.data.actions:
                    action[armature_key] = armature_key
                    tool.target_object.animation_data.action = action
                    bpy.data.actions[action.name].name = "T-Pose"
                bpy.ops.wm_ggt.prepare_mixamo_rig('EXEC_DEFAULT')

        return {'FINISHED'}