Skip to content
Snippets Groups Projects
scene_amaranth_toolset.py 91.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • Pablo Vazquez's avatar
    Pablo Vazquez committed
            if object:
                return object.mode == 'EDIT' and object.type == 'MESH'
            return False
    
        def execute(self, context):
            threshold = 1e-6
    
            object = context.object
            bm = bmesh.from_edit_mesh(object.data)
    
            for v1 in bm.verts:
                if v1.co[0] < threshold:
                    continue
                if not v1.select:
                    continue
    
                closest_vert = None
                closest_distance = -1
                for v2 in bm.verts:
                    if v1 == v2:
                        continue
                    if v2.co[0] > threshold:
                        continue
                    if not v2.select:
                        continue
    
                    mirror_coord = Vector(v2.co)
                    mirror_coord[0] *= -1
                    distance = (mirror_coord - v1.co).length_squared
                    if closest_vert is None or distance < closest_distance:
                        closest_distance = distance
                        closest_vert = v2
    
                if closest_vert:
                    closest_vert.select = False
                    closest_vert.co = Vector(v1.co)
                    closest_vert.co[0] *= -1
                v1.select = False
    
            for v1 in bm.verts:
                if v1.select:
                    closest_vert = None
                    closest_distance = -1
                    for v2 in bm.verts:
                        if v1 != v2:
                            mirror_coord = Vector(v2.co)
                            mirror_coord[0] *= -1
                            distance = (mirror_coord - v1.co).length_squared
                            if closest_vert is None or distance < closest_distance:
                                closest_distance = distance
                                closest_vert = v2
                    if closest_vert:
                        v1.select = False
                        v1.co = Vector(closest_vert.co)
                        v1.co[0] *= -1
    
            bm.select_flush_mode()
            bmesh.update_edit_mesh(object.data)
    
            return {'FINISHED'}
    # // FEATURE: Mesh Symmetry Tools by Sergey Sharybin
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    # FEATURE: Cycles Render Sampling Extra
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    def render_cycles_scene_samples(self, context):
    
        layout = self.layout
    
        scenes = bpy.data.scenes
        scene = context.scene
        cscene = scene.cycles
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        render = scene.render
        list_sampling = scene.amaranth_cycles_list_sampling
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        if cscene.progressive == 'BRANCHED_PATH':
            layout.separator()
            split = layout.split()
            col = split.column()
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            col.operator(
                AMTH_RENDER_OT_cycles_samples_percentage_set.bl_idname,
                text="%s" % 'Set as Render Samples' if cscene.use_samples_final else 'Set New Render Samples',
                icon="%s" % 'PINNED' if cscene.use_samples_final else 'UNPINNED')
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            col = split.column()
            row = col.row(align=True)
            row.enabled = True if scene.get('amth_cycles_samples_final') else False
    
            row.operator(
                AMTH_RENDER_OT_cycles_samples_percentage.bl_idname,
                text="100%").percent=100
            row.operator(
                AMTH_RENDER_OT_cycles_samples_percentage.bl_idname,
                text="75%").percent=75
            row.operator(
                AMTH_RENDER_OT_cycles_samples_percentage.bl_idname,
                text="50%").percent=50
            row.operator(
                AMTH_RENDER_OT_cycles_samples_percentage.bl_idname,
                text="25%").percent=25
    
        # List Lamps
        if (len(scene.render.layers) > 1) or \
            (len(bpy.data.scenes) > 1):
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            layout.separator()
            box = layout.box()
            row = box.row(align=True)
            col = row.column(align=True)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            row = col.row(align=True)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            row.alignment = 'LEFT'
            row.prop(scene, 'amaranth_cycles_list_sampling',
                        icon="%s" % 'TRIA_DOWN' if list_sampling else 'TRIA_RIGHT',
                        emboss=False)
    
        if list_sampling:
            if len(scene.render.layers) == 1 and \
                render.layers[0].samples == 0:
                pass
            else:
                col.separator()
                col.label(text="RenderLayers:", icon='RENDERLAYERS')
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                for rl in scene.render.layers:
                    row = col.row(align=True)
                    row.label(rl.name, icon='BLANK1')
                    row.prop(rl, "samples", text="%s" %
                        "Samples" if rl.samples > 0 else "Automatic (%s)" % (
                            cscene.aa_samples if cscene.progressive == 'BRANCHED_PATH' else cscene.samples))
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            if (len(bpy.data.scenes) > 1):
                col.separator()
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                col.label(text="Scenes:", icon='SCENE_DATA')
                row = col.row(align=True)
    
                if cscene.progressive == 'PATH':
                    for s in bpy.data.scenes:
                        if s != scene:
                            row = col.row(align=True)
                            if s.render.engine == 'CYCLES':
                                cscene = s.cycles
    
                                row.label(s.name)
                                row.prop(cscene, "samples", icon='BLANK1')
                            else:
                                row.label(text="Scene: '%s' is not using Cycles" % s.name)
                else:
                    for s in bpy.data.scenes:
                        if s != scene:
                            row = col.row(align=True)
                            if s.render.engine == 'CYCLES':
                                cscene = s.cycles
    
                                row.label(s.name, icon='BLANK1')
                                row.prop(cscene, "aa_samples",
                                    text="AA Samples")
                            else:
                                row.label(text="Scene: '%s' is not using Cycles" % s.name)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
    # // FEATURE: Cycles Render Sampling Extra
    
    # FEATURE: Motion Paths Extras
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_POSE_OT_paths_clear_all(Operator):
    
        """Clear motion paths from all bones"""
        bl_idname = "pose.paths_clear_all"
        bl_label = "Clear All Motion Paths"
        bl_options = {'UNDO'}
    
        @classmethod
        def poll(cls, context):
            return context.mode == 'POSE'
    
        def execute(self, context):
            #silly but works
            for b in context.object.data.bones:
                b.select = True
                bpy.ops.pose.paths_clear()
                b.select = False
            return {'FINISHED'}
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_POSE_OT_paths_frame_match(Operator):
    
        """Match Start/End frame of scene to motion path range"""
        bl_idname = "pose.paths_frame_match"
        bl_label = "Match Frame Range"
        bl_options = {'UNDO'}
    
        def execute(self, context):
            avs = context.object.pose.animation_visualization
            scene = context.scene
    
            if avs.motion_path.type == 'RANGE':
                if scene.use_preview_range:
                    avs.motion_path.frame_start = scene.frame_preview_start
                    avs.motion_path.frame_end = scene.frame_preview_end
                else:
                    avs.motion_path.frame_start = scene.frame_start
                    avs.motion_path.frame_end = scene.frame_end
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            else:
    
                if scene.use_preview_range:
                    avs.motion_path.frame_before = scene.frame_preview_start
                    avs.motion_path.frame_after = scene.frame_preview_end
                else:
                    avs.motion_path.frame_before = scene.frame_start
                    avs.motion_path.frame_after = scene.frame_end
    
            return {'FINISHED'}
    
    def pose_motion_paths_ui(self, context):
    
        layout = self.layout
        scene = context.scene
        avs = context.object.pose.animation_visualization
        if context.active_pose_bone:
            mpath = context.active_pose_bone.motion_path
        layout.separator()    
        layout.label(text="Motion Paths Extras:")
    
        split = layout.split()
    
        col = split.column(align=True)
    
        if context.selected_pose_bones:
            if mpath:
                sub = col.row(align=True)
                sub.operator("pose.paths_update", text="Update Path", icon='BONE_DATA')
                sub.operator("pose.paths_clear", text="", icon='X')
            else:
                col.operator("pose.paths_calculate", text="Calculate Path", icon='BONE_DATA')
        else:
            col.label(text="Select Bones First", icon="ERROR")
    
        col = split.column(align=True)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        col.operator(AMTH_POSE_OT_paths_frame_match.bl_idname,
    
            text="{}".format( "Set Preview Frame Range"
                    if scene.use_preview_range else "Set Frame Range"),
            icon="{}".format("PREVIEW_RANGE"
                    if scene.use_preview_range else "TIME"))
    
        col = layout.column()
        row = col.row(align=True)
    
        if avs.motion_path.type == 'RANGE':
            row.prop(avs.motion_path, "frame_start", text="Start")
            row.prop(avs.motion_path, "frame_end", text="End")
        else:
            row.prop(avs.motion_path, "frame_before", text="Before")
            row.prop(avs.motion_path, "frame_after", text="After")
    
        layout.separator()
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        layout.operator(AMTH_POSE_OT_paths_clear_all.bl_idname, icon="X")
    
    # // FEATURE: Motion Paths Extras
    
    # FEATURE: Final Render Resolution Display
    def render_final_resolution_ui(self, context):
    
        rd = context.scene.render
        layout = self.layout
    
        final_res_x = (rd.resolution_x * rd.resolution_percentage) / 100
        final_res_y = (rd.resolution_y * rd.resolution_percentage) / 100
    
        if rd.use_border:
           final_res_x_border = round((final_res_x * (rd.border_max_x - rd.border_min_x)))
           final_res_y_border = round((final_res_y * (rd.border_max_y - rd.border_min_y)))
           layout.label(text="Final Resolution: {} x {} [Border: {} x {}]".format(
                 str(final_res_x)[:-2], str(final_res_y)[:-2],
                 str(final_res_x_border), str(final_res_y_border)))
        else:
            layout.label(text="Final Resolution: {} x {}".format(
                 str(final_res_x)[:-2], str(final_res_y)[:-2]))
    # // FEATURE: Final Render Resolution Display
    
    # FEATURE: Shader Nodes Extra Info
    def node_shader_extra(self, context):
    
        if context.space_data.tree_type == 'ShaderNodeTree':
            ob = context.active_object
            snode = context.space_data
            layout = self.layout
    
            if ob and snode.shader_type != 'WORLD':
                if ob.type == 'LAMP':
                    layout.label(text="%s" % ob.name,
                                 icon="LAMP_%s" % ob.data.type)        
                else:
                    layout.label(text="%s" % ob.name,
                                 icon="OUTLINER_DATA_%s" % ob.type)
                 
    
    # // FEATURE: Shader Nodes Extra Info
    
    # FEATURE: Scene Debug
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_SCENE_OT_cycles_shader_list_nodes(Operator):
    
        """List Cycles materials containing a specific shader"""
        bl_idname = "scene.cycles_list_nodes"
        bl_label = "List Materials"
    
        materials = []
    
    
        @classmethod
        def poll(cls, context):
            return context.scene.render.engine == 'CYCLES'
    
        def execute(self, context):
            node_type = context.scene.amaranth_cycles_node_types
            roughness = False
    
            self.__class__.materials = []
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            shaders_roughness = ['BSDF_GLOSSY','BSDF_DIFFUSE','BSDF_GLASS']
    
    
            print("\n=== Cycles Shader Type: %s === \n" % node_type)
    
            for ma in bpy.data.materials:
                if ma.node_tree:
                    nodes = ma.node_tree.nodes
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                    
                    print_unconnected = ('Note: \nOutput from "%s" node' % node_type,
                                            'in material "%s"' % ma.name, 'not connected\n')
    
    
                    for no in nodes:
                        if no.type == node_type:
                            for ou in no.outputs:
                                if ou.links:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                    connected = True
                                    if no.type in shaders_roughness:
    
                                        roughness = 'R: %.4f' % no.inputs['Roughness'].default_value
                                    else:
                                        roughness = False
                                else:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                    connected = False
                                    print(print_unconnected)
    
                                if ma.name not in self.__class__.materials:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                    self.__class__.materials.append('%s%s [%s] %s%s%s' % (
    
                                        '[L] ' if ma.library else '',
                                        ma.name, ma.users,
                                        '[F]' if ma.use_fake_user else '',
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                        ' - [%s]' % roughness if roughness else '',
                                        ' * Output not connected' if not connected else ''))
    
                        elif no.type == 'GROUP':
                            if no.node_tree:
                                for nog in no.node_tree.nodes:
                                    if nog.type == node_type:
                                        for ou in nog.outputs:
                                            if ou.links:
                                                connected = True
                                                if nog.type in shaders_roughness:
                                                    roughness = 'R: %.4f' % nog.inputs['Roughness'].default_value
                                                else:
                                                    roughness = False
                                            else:
                                                connected = False
                                                print(print_unconnected)
    
                                            if ma.name not in self.__class__.materials:
                                                self.__class__.materials.append('%s%s%s [%s] %s%s%s' % (
                                                    '[L] ' if ma.library else '',
                                                    'Node Group:  %s%s  ->  ' % (
                                                        '[L] ' if no.node_tree.library else '',
                                                        no.node_tree.name),
                                                    ma.name, ma.users,
                                                    '[F]' if ma.use_fake_user else '',
                                                    ' - [%s]' % roughness if roughness else '',
                                                    ' * Output not connected' if not connected else ''))
    
                        self.__class__.materials = sorted(list(set(self.__class__.materials)))
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            if len(self.__class__.materials) == 0:
    
                self.report({"INFO"}, "No materials with nodes type %s found" % node_type)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                print("* A total of %d %s using %s was found \n" % (
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                        len(self.__class__.materials),
                        "material" if len(self.__class__.materials) == 1 else "materials",
    
                        node_type))
    
                for mat in self.__class__.materials:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                    print('%02d. %s' % (count+1, self.__class__.materials[count]))
    
                    count += 1
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            self.__class__.materials = sorted(list(set(self.__class__.materials)))
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_SCENE_OT_cycles_shader_list_nodes_clear(Operator):
    
        """Clear the list below"""
        bl_idname = "scene.cycles_list_nodes_clear"
        bl_label = "Clear Materials List"
        
        def execute(self, context):
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            AMTH_SCENE_OT_cycles_shader_list_nodes.materials[:] = []
    
            print("* Cleared Cycles Materials List")
    
            return {'FINISHED'}
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_SCENE_OT_amaranth_debug_lamp_select(Operator):
    
        '''Select Lamp'''
        bl_idname = "scene.amaranth_debug_lamp_select"
        bl_label = "Select Lamp"
        lamp = bpy.props.StringProperty()
     
        def execute(self, context):
            if self.lamp:
                lamp = bpy.data.objects[self.lamp]
    
                bpy.ops.object.select_all(action='DESELECT')
                lamp.select = True
                context.scene.objects.active = lamp
    
    
            return{'FINISHED'}
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_SCENE_OT_list_missing_node_links(Operator):
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        '''Print a list of missing node links'''
        bl_idname = "scene.list_missing_node_links"
        bl_label = "List Missing Node Links"
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        count_groups = 0
        count_images = 0
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        count_image_node_unlinked = 0
    
    
        def execute(self, context):
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            missing_groups = []
            missing_images = []
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            image_nodes_unlinked = []
    
            libraries = []
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            self.__class__.count_groups = 0
            self.__class__.count_images = 0
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            self.__class__.count_image_node_unlinked = 0
    
    
            for ma in bpy.data.materials:
                if ma.node_tree:
                    for no in ma.node_tree.nodes:
                        if no.type == 'GROUP':
                            if not no.node_tree:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                self.__class__.count_groups += 1
    
                                users_ngroup = []
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                for ob in bpy.data.objects:
                                    if ob.material_slots and ma.name in ob.material_slots:
                                        users_ngroup.append("%s%s%s" % (
                                            "[L] " if ob.library else "",
                                            "[F] " if ob.use_fake_user else "",
                                            ob.name))
    
                                missing_groups.append("NG: %s%s%s [%s]%s%s\n" % (
    
                                    "[L] " if ma.library else "",
                                    "[F] " if ma.use_fake_user else "",
                                    ma.name, ma.users,
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                    "\nLI: %s" % 
                                    ma.library.filepath if ma.library else "",
                                    "\nOB: %s" % ',  '.join(users_ngroup) if users_ngroup else ""))
    
    
                                if ma.library:
                                    libraries.append(ma.library.filepath)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                        if no.type == 'TEX_IMAGE':
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
                            outputs_empty = not no.outputs['Color'].is_linked and not no.outputs['Alpha'].is_linked
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                            if no.image:
                                import os.path
                                image_path_exists = os.path.exists(
                                                        bpy.path.abspath(
                                                            no.image.filepath, library=no.image.library))
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                            if outputs_empty or not \
                               no.image or not \
                               image_path_exists:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
                                users_images = []
    
                                for ob in bpy.data.objects:
                                    if ob.material_slots and ma.name in ob.material_slots:
                                        users_images.append("%s%s%s" % (
                                            "[L] " if ob.library else "",
                                            "[F] " if ob.use_fake_user else "",
                                            ob.name))
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                if outputs_empty:
                                    self.__class__.count_image_node_unlinked += 1
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                    image_nodes_unlinked.append("%s%s%s%s%s [%s]%s%s%s%s\n" % (
                                        "NO: %s" % no.name,
                                        "\nMA: ",
                                        "[L] " if ma.library else "",
                                        "[F] " if ma.use_fake_user else "",
                                        ma.name, ma.users,
                                        "\nLI: %s" % 
                                        ma.library.filepath if ma.library else "",
                                        "\nIM: %s" % no.image.name if no.image else "",
                                        "\nLI: %s" % no.image.filepath if no.image and no.image.filepath else "",
                                        "\nOB: %s" % ',  '.join(users_images) if users_images else ""))
                                
    
                                if not no.image or not image_path_exists:
                                    self.__class__.count_images += 1
    
                                    missing_images.append("MA: %s%s%s [%s]%s%s%s%s\n" % (
                                        "[L] " if ma.library else "",
                                        "[F] " if ma.use_fake_user else "",
                                        ma.name, ma.users,
                                        "\nLI: %s" % 
                                        ma.library.filepath if ma.library else "",
                                        "\nIM: %s" % no.image.name if no.image else "",
                                        "\nLI: %s" % no.image.filepath if no.image and no.image.filepath else "",
                                        "\nOB: %s" % ',  '.join(users_images) if users_images else ""))
    
                                    if ma.library:
                                        libraries.append(ma.library.filepath)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            # Remove duplicates and sort
            missing_groups = sorted(list(set(missing_groups)))
            missing_images = sorted(list(set(missing_images)))
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            image_nodes_unlinked = sorted(list(set(image_nodes_unlinked)))
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            libraries = sorted(list(set(libraries)))
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            print("\n\n== %s missing image %s, %s missing node %s and %s image %s unlinked ==" %
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                ("No" if self.__class__.count_images == 0 else str(self.__class__.count_images),
                "node" if self.__class__.count_images == 1 else "nodes",
                "no" if self.__class__.count_groups == 0 else str(self.__class__.count_groups),
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                "group" if self.__class__.count_groups == 1 else "groups",
                "no" if self.__class__.count_image_node_unlinked == 0 else str(self.__class__.count_image_node_unlinked),
                "node" if self.__class__.count_groups == 1 else "nodes"))
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
            # List Missing Node Groups
            if missing_groups:
                print("\n* Missing Node Group Links [NG]\n")
                for mig in missing_groups:
                    print(mig)
    
            # List Missing Image Nodes
            if missing_images:
                print("\n* Missing Image Nodes Link [IM]\n")
    
                for mii in missing_images:
                    print(mii)
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            # List Image Nodes with its outputs unlinked
            if image_nodes_unlinked:
                print("\n* Image Nodes Unlinked [IM]\n")
    
                for nou in image_nodes_unlinked:
                    print(nou)
    
            if missing_groups or \
               missing_images or \
               image_nodes_unlinked:
    
                if libraries:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                    print("\nThat's bad, run check on %s:" % (
    
                        "this library" if len(libraries) == 1 else "these libraries"))
                    for li in libraries:
                        print(li)
            else:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                self.report({"INFO"}, "Yay! No missing node links")            
    
            print("\n")
    
            if missing_groups and missing_images:
                self.report({"WARNING"}, "%d missing image %s and %d missing node %s found" %
                    (self.__class__.count_images, "node" if self.__class__.count_images == 1 else "nodes",
                    self.__class__.count_groups, "group" if self.__class__.count_groups == 1 else "groups"))
    
            return{'FINISHED'}
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_SCENE_OT_list_missing_material_slots(Operator):
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        '''List objects with empty material slots'''
        bl_idname = "scene.list_missing_material_slots"
        bl_label = "List Empty Material Slots"
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        objects = []
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        libraries = []
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        def execute(self, context):
            self.__class__.objects = []
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            self.__class__.libraries = []
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
            for ob in bpy.data.objects:
                for ma in ob.material_slots:
                    if not ma.material:
                        self.__class__.objects.append('%s%s' % (
                            '[L] ' if ob.library else '',
                            ob.name))
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                        if ob.library:
                            self.__class__.libraries.append(ob.library.filepath)
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            self.__class__.objects = sorted(list(set(self.__class__.objects)))
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            self.__class__.libraries = sorted(list(set(self.__class__.libraries)))
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
            if len(self.__class__.objects) == 0:
                self.report({"INFO"}, "No objects with empty material slots found")
            else:
                print("\n* A total of %d %s with empty material slots was found \n" % (
                        len(self.__class__.objects),
                        "object" if len(self.__class__.objects) == 1 else "objects"))
    
                count = 0
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                count_lib = 0
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
                for obs in self.__class__.objects:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                    print('%02d. %s' % (
                        count+1, self.__class__.objects[count]))
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                    count += 1
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
                if self.__class__.libraries:
                    print("\n\n* Check %s:\n" % 
                        ("this library" if len(self.__class__.libraries) == 1
                            else "these libraries"))
    
                    for libs in self.__class__.libraries:
                        print('%02d. %s' % (
                            count_lib+1, self.__class__.libraries[count_lib]))
                        count_lib += 1
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                print("\n")
    
            return{'FINISHED'}
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_SCENE_OT_list_missing_material_slots_clear(Operator):
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        """Clear the list below"""
        bl_idname = "scene.list_missing_material_slots_clear"
        bl_label = "Clear Empty Material Slots List"
        
        def execute(self, context):
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            AMTH_SCENE_OT_list_missing_material_slots.objects[:] = []
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            print("* Cleared Empty Material Slots List")
            return {'FINISHED'}
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_SCENE_OT_blender_instance_open(Operator):
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
        '''Open in a new Blender instance'''
        bl_idname = "scene.blender_instance_open"
        bl_label = "Open Blender Instance"
        filepath = bpy.props.StringProperty()
     
        def execute(self, context):
            if self.filepath:
                filepath = bpy.path.abspath(self.filepath)
    
                import subprocess
                try:
                    subprocess.Popen([bpy.app.binary_path, filepath])
                except:
                    print("Error on the new Blender instance")
                    import traceback
                    traceback.print_exc()
    
    
            return{'FINISHED'}
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_SCENE_PT_scene_debug(Panel):
    
        '''Scene Debug'''
        bl_label = 'Scene Debug'
        bl_space_type = "PROPERTIES"
        bl_region_type = "WINDOW"
        bl_context = "scene"
    
        def draw(self, context):
            layout = self.layout
            scene = context.scene
            objects =  bpy.data.objects
            ob_act = context.active_object
            images = bpy.data.images
            lamps = bpy.data.lamps
            images_missing = []
            list_lamps = scene.amaranth_debug_scene_list_lamps
            list_missing_images = scene.amaranth_debug_scene_list_missing_images
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            materials = AMTH_SCENE_OT_cycles_shader_list_nodes.materials
            materials_count = len(AMTH_SCENE_OT_cycles_shader_list_nodes.materials)
            missing_material_slots_obs = AMTH_SCENE_OT_list_missing_material_slots.objects
            missing_material_slots_count = len(AMTH_SCENE_OT_list_missing_material_slots.objects)
            missing_material_slots_lib = AMTH_SCENE_OT_list_missing_material_slots.libraries
    
            engine = scene.render.engine
    
            # List Lamps
            box = layout.box()
            row = box.row(align=True)
            split = row.split()
            col = split.column()
            
            if lamps:
                row = col.row(align=True)
                row.alignment = 'LEFT'
                row.prop(scene, 'amaranth_debug_scene_list_lamps',
                            icon="%s" % 'TRIA_DOWN' if list_lamps else 'TRIA_RIGHT',
                            emboss=False)
    
                if objects and list_lamps:
                    row = box.row(align=True)
                    split = row.split(percentage=0.42)
                    col = split.column()
                    col.label(text="Name")
    
                    split = split.split(percentage=0.1)
                    col = split.column()
                    col.label(text="", icon="BLANK1")
                    if engine in ['CYCLES', 'BLENDER_RENDER']:
                        if engine == 'BLENDER_RENDER':
                            split = split.split(percentage=0.7)
                        else:
                            split = split.split(percentage=0.35)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                        col = split.column()
    
                        col.label(text="Samples")
    
                    if engine == 'CYCLES':
                        split = split.split(percentage=0.35)
                        col = split.column()
                        col.label(text="Size")
    
                    split = split.split(percentage=0.8)
                    col = split.column()
                    col.label(text="Visibility")
    
                    for ob in objects:
                        if ob and ob.type == 'LAMP':
                            lamp = ob.data
                            clamp = ob.data.cycles
    
                            row = box.row(align=True)
                            split = row.split(percentage=0.5)
                            col = split.column()
                            row = col.row()
                            row.alignment = 'LEFT'
                            row.operator("scene.amaranth_debug_lamp_select",
                                        text='%s %s%s' % (
                                            " [L] " if ob.library else "",
                                            ob.name,
                                            "" if ob.name in context.scene.objects else " [Not in Scene]"),
                                        icon="LAMP_%s" % ob.data.type,
                                        emboss=False).lamp = ob.name
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                            if ob.library:
                                row = col.row(align=True)
                                row.alignment = "LEFT"
                                row.operator(AMTH_SCENE_OT_blender_instance_open.bl_idname,
                                             text=ob.library.filepath,
                                             icon="LINK_BLEND",
                                             emboss=False).filepath=ob.library.filepath
    
    
                            if engine == 'CYCLES':
                                split = split.split(percentage=0.35)
                                col = split.column()
                                if scene.cycles.progressive == 'BRANCHED_PATH':
                                    col.prop(clamp, "samples", text="")
                                if scene.cycles.progressive == 'PATH':
                                   col.label(text="N/A")
                               
                            if engine == 'BLENDER_RENDER':
                                split = split.split(percentage=0.7)
                                col = split.column()
                                if lamp.type == 'HEMI':
                                    col.label(text="Not Available")
                                elif lamp.type == 'AREA' and lamp.shadow_method == 'RAY_SHADOW':
                                    row = col.row(align=True)
                                    row.prop(lamp, "shadow_ray_samples_x", text="X")
                                    if lamp.shape == 'RECTANGLE':
                                        row.prop(lamp, "shadow_ray_samples_y", text="Y")
                                elif lamp.shadow_method == 'RAY_SHADOW':
                                    col.prop(lamp, "shadow_ray_samples", text="Ray Samples")
                                elif lamp.shadow_method == 'BUFFER_SHADOW':
                                    col.prop(lamp, "shadow_buffer_samples", text="Buffer Samples")
                                else:
                                    col.label(text="No Shadow")
    
                            if engine == 'CYCLES':
                                split = split.split(percentage=0.4)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                col = split.column()
    
                                if lamp.type in ['POINT','SUN', 'SPOT']:
                                    col.label(text="%.2f" % lamp.shadow_soft_size)
                                elif lamp.type == 'HEMI':
                                    col.label(text="N/A")
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                elif lamp.type == 'AREA' and lamp.shape == 'RECTANGLE':
                                    col.label(text="%.2fx%.2f" % (lamp.size, lamp.size_y))
    
                                else:
                                    col.label(text="%.2f" % lamp.size)
    
                            split = split.split(percentage=0.8)
                            col = split.column()
                            row = col.row(align=True)
                            row.prop(ob, "hide", text="", emboss=False)
                            row.prop(ob, "hide_render", text="", emboss=False)
    
                            split = split.split(percentage=0.3)
                            col = split.column()
                            col.label(text="", icon="%s" % "TRIA_LEFT" if ob == ob_act else "BLANK1")
    
            else:
                row = col.row(align=True)
                row.alignment = 'LEFT'
                row.label(text="Lamps List", icon="RIGHTARROW_THIN")
    
                split = split.split()
                col = split.column()
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
    
                col.label(text="No Lamps", icon="LAMP_DATA")
    
            # List Missing Images
    
            box = layout.box()
            row = box.row(align=True)
            split = row.split()
            col = split.column()
    
    
            if images:
                import os.path
    
                for im in images:
                    if im.type not in ['UV_TEST', 'RENDER_RESULT', 'COMPOSITING']: 
                        if not os.path.exists(bpy.path.abspath(im.filepath, library=im.library)):
                            images_missing.append(["%s%s [%s]%s" % (
                                '[L] ' if im.library else '',
                                im.name, im.users,
                                ' [F]' if im.use_fake_user else ''),
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                im.filepath if im.filepath else 'No Filepath',
                                im.library.filepath if im.library else ''])
    
    
                if images_missing:
                    row = col.row(align=True)
                    row.alignment = 'LEFT'
                    row.prop(scene, 'amaranth_debug_scene_list_missing_images',
                                icon="%s" % 'TRIA_DOWN' if list_missing_images else 'TRIA_RIGHT',
                                emboss=False)
    
                    split = split.split()
                    col = split.column()
    
                    col.label(text="%s missing %s" % (
                                 str(len(images_missing)),
                                 'image' if len(images_missing) == 1 else 'images'),
                                 icon="ERROR")
    
                    if list_missing_images:
                        col = box.column(align=True)
                        for mis in images_missing:
                            col.label(text=mis[0],
                             icon="IMAGE_DATA")
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                            col.label(text=mis[1], icon="LIBRARY_DATA_DIRECT")
                            if mis[2]:
                                row = col.row(align=True)
                                row.alignment = "LEFT"
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                row.operator(AMTH_SCENE_OT_blender_instance_open.bl_idname,
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                             text=mis[2],
                                             icon="LINK_BLEND",
                                             emboss=False).filepath=mis[2]
    
                            col.separator()
                else:
                    row = col.row(align=True)
                    row.alignment = 'LEFT'
                    row.label(text="Great! No missing images", icon="RIGHTARROW_THIN")
    
                    split = split.split()
                    col = split.column()
    
                    col.label(text="%s %s loading correctly" % (
                                 str(len(images)),
                                 'image' if len(images) == 1 else 'images'),
                                 icon="IMAGE_DATA")
    
            else:
                row = col.row(align=True)
                row.alignment = 'LEFT'
                row.label(text="No images loaded yet", icon="RIGHTARROW_THIN")
    
            # List Cycles Materials by Shader
            if engine == 'CYCLES':
                box = layout.box()
                split = box.split()
                col = split.column(align=True)
                col.prop(scene, 'amaranth_cycles_node_types',
                    icon="MATERIAL")
    
                row = split.row(align=True)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                row.operator(AMTH_SCENE_OT_cycles_shader_list_nodes.bl_idname,
    
                                icon="SORTSIZE",
                                text="List Materials Using Shader")
                if materials_count != 0: 
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                    row.operator(AMTH_SCENE_OT_cycles_shader_list_nodes_clear.bl_idname,
    
                                    icon="X", text="")
                col.separator()
    
                try:
                    materials
                except NameError:
                    pass
                else:
                    if materials_count != 0: 
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                        col = box.column(align=True)
    
                        count = 0
                        col.label(text="%s %s found" % (materials_count,
                            'material' if materials_count == 1 else 'materials'), icon="INFO")
                        for mat in materials:
                            count += 1
                            col.label(text='%s' % (materials[count-1]), icon="MATERIAL")
    
            # List Missing Node Trees
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            box = layout.box()
            row = box.row(align=True)
            split = row.split()
            col = split.column(align=True)
    
            split = col.split()
            split.label(text="Node Links")
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            split.operator(AMTH_SCENE_OT_list_missing_node_links.bl_idname,
    
                            icon="NODETREE")
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            if AMTH_SCENE_OT_list_missing_node_links.count_groups != 0 or \
                AMTH_SCENE_OT_list_missing_node_links.count_images != 0 or \
                AMTH_SCENE_OT_list_missing_node_links.count_image_node_unlinked != 0:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                col.label(text="Warning! Check Console", icon="ERROR")
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            if AMTH_SCENE_OT_list_missing_node_links.count_groups != 0:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                col.label(text="%s" % ("%s node %s missing link" % (
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                         str(AMTH_SCENE_OT_list_missing_node_links.count_groups),
                         "group" if AMTH_SCENE_OT_list_missing_node_links.count_groups == 1 else "groups")),
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                         icon="NODETREE")
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            if AMTH_SCENE_OT_list_missing_node_links.count_images != 0:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                col.label(text="%s" % ("%s image %s missing link" % (
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                         str(AMTH_SCENE_OT_list_missing_node_links.count_images),
                         "node" if AMTH_SCENE_OT_list_missing_node_links.count_images == 1 else "nodes")),
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                         icon="IMAGE_DATA")
    
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            if AMTH_SCENE_OT_list_missing_node_links.count_image_node_unlinked != 0:
                col.label(text="%s" % ("%s image %s with no output conected" % (
                         str(AMTH_SCENE_OT_list_missing_node_links.count_image_node_unlinked),
                         "node" if AMTH_SCENE_OT_list_missing_node_links.count_image_node_unlinked == 1 else "nodes")),
                         icon="NODE")
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
            # List Empty Materials Slots
            box = layout.box()
            split = box.split()
            col = split.column(align=True)
            col.label(text="Material Slots")
    
            row = split.row(align=True)
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            row.operator(AMTH_SCENE_OT_list_missing_material_slots.bl_idname,
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                            icon="MATERIAL",
                            text="List Empty Materials Slots")
            if missing_material_slots_count != 0: 
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                row.operator(AMTH_SCENE_OT_list_missing_material_slots_clear.bl_idname,
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                                icon="X", text="")
            col.separator()
    
            try:
                missing_material_slots_obs
            except NameError:
                pass
            else:
                if missing_material_slots_count != 0: 
                    col = box.column(align=True)
                    count = 0
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                    count_lib = 0
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                    col.label(text="%s %s with empty material slots found" % (
                        missing_material_slots_count,
                        'object' if missing_material_slots_count == 1 else 'objects'),
                        icon="INFO")
    
                    for obs in missing_material_slots_obs:
                        count += 1
                        col.label(text='%s' % (
                            missing_material_slots_obs[count-1]),
                            icon="OBJECT_DATA")
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                    if missing_material_slots_lib:
                        col.separator()
                        col.label("Check %s:" % (
                            "this library" if
                                len(missing_material_slots_lib) == 1
                                    else "these libraries"))
                        
                        for libs in missing_material_slots_lib:
                            count_lib += 1
                            row = col.row(align=True)
                            row.alignment = "LEFT"
                            row.operator(AMTH_SCENE_OT_blender_instance_open.bl_idname,
                                         text=missing_material_slots_lib[count_lib-1],
                                         icon="LINK_BLEND",
                                         emboss=False).filepath=missing_material_slots_lib[count_lib-1]
    
    
    # // FEATURE: Scene Debug
    
    # FEATURE: Dupli  Group Path
    def ui_dupli_group_library_path(self, context):
    
        ob = context.object
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    
        row = self.layout.row()
        row.alignment = 'LEFT'
    
    
        if ob and ob.dupli_group and ob.dupli_group.library:
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
            lib = ob.dupli_group.library.filepath
    
            row.operator(AMTH_SCENE_OT_blender_instance_open.bl_idname,
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
                text="Library: %s" % lib,
                emboss=False,
                icon="LINK_BLEND").filepath=lib
    
    
    # // FEATURE: Dupli  Group Path
    
    # FEATURE: Color Management Presets
    
    Pablo Vazquez's avatar
    Pablo Vazquez committed
    class AMTH_SCENE_MT_color_management_presets(Menu):
    
        """List of Color Management presets"""
        bl_label = "Color Management Presets"
        preset_subdir = "color"
        preset_operator = "script.execute_preset"
        draw = Menu.draw_preset