OverviewFilesCommitsIssuesDocsReleasesPeers

hardops / operators / misc / bloom_toggle.py

129 lines · python ref:
import bpy


class HOPS_OT_Bloom_Toggle(bpy.types.Operator):
    bl_idname = "hops.bloom_toggle"
    bl_label = "Toggle Compositor Bloom in Viewvport"
    bl_options = {"REGISTER", "UNDO"}
    bl_description = """Toggle Bloom in current compsitor node tree"""

    threshold: bpy.props.FloatProperty(
        name = "Threshold",
        description = 'Bloom Threshold',
        min = 0.0,
        default = 0.2)

    @classmethod
    def poll(cls, context):
        return bpy.app.version >= (4, 0, 0)

    def draw(self, context):
        if not self.bloom_node: return
        self.layout.prop(self, 'threshold')


    def execute(self, context):
        scene = context.scene
        context.space_data.shading.use_compositor = 'ALWAYS'
        self.bloom_node = ''


        composite = None
        render_layer = None
        viewers = []
        out_name= ''

        if bpy.app.version[0] < 5:
            scene.use_nodes = True
            node_tree = scene.node_tree
            out_name = 'CompositorNodeComposite'
        else:
            node_tree = scene.compositing_node_group
            if not node_tree:
                node_tree = scene.compositing_node_group = bpy.data.node_groups.new('Bloom', 'CompositorNodeTree')
            out_name = 'NodeGroupOutput'


        for node in node_tree.nodes:
            if node.type in {"COMPOSITE", "GROUP_OUTPUT"} and not composite:
                if node.inputs[0].is_linked:
                    composite = node

            if node.type == 'VIEWER':
                viewers.append(node)

        for node in viewers:
            node_tree.nodes.remove(node)

        # if there is not composite node assume whole tree is invalid and make basic one
        if not composite:
            composite = node_tree.nodes.new(out_name)

        # in 5.0 there can be multiple, but not using 1st is cringe
        if not composite.inputs[0].is_linked:
            render_layer = node_tree.nodes.new("CompositorNodeRLayers")
            composite.location.x = render_layer.width * 2

            # in 5.X empty output has no color socket
            if bpy.app.version[0] > 4:
                node_tree.interface.new_socket('Image', in_out='OUTPUT', socket_type='NodeSocketColor')

            input = composite.inputs[0]
            output = render_layer.outputs[0]
            node_tree.links.new(input, output)

        comp_input = composite.inputs[0]
        if comp_input.is_linked:
            from_socket = comp_input.links[0].from_socket
            to_socket = comp_input.links[0].to_socket
            link = comp_input.links[0]
            input_node = comp_input.links[0].from_node

            # it's not glare bloom inject it
            if input_node.type != 'GLARE' or glare_type(input_node) !='BLOOM':
                glare = node_tree.nodes.new("CompositorNodeGlare")
                if bpy.app.version[0] < 5:
                    glare.glare_type = 'BLOOM'
                    if 'Threshold' in glare.inputs:
                        glare.inputs['Threshold'].default_value = self.threshold
                    else:
                        glare.threshold = self.threshold

                else:
                    glare.inputs['Type'].default_value = 'Bloom'
                    glare.inputs['Threshold'].default_value = self.threshold


                node_tree.links.remove(link)
                node_tree.links.new(glare.inputs[0], from_socket)
                node_tree.links.new(glare.outputs[0], to_socket)

                from_node = from_socket.node
                to_node = to_socket.node
                glare.location.x = from_node.location.x + from_node.width + 100
                to_node.location.x = glare.location.x + glare.width + 100
                self.bloom_node = glare.name

            # otherwise toggle node
            else:
                input_node.mute = not input_node.mute

                if not input_node.mute:
                    self.bloom_node = input_node.name
                    if 'Threshold' in input_node.inputs:
                        input_node.inputs['Threshold'].default_value = self.threshold
                    else:
                        input_node.threshold = self.threshold

        return {"FINISHED"}


def glare_type(node)-> str:
    '''Assume node is GLARE type'''
    if bpy.app.version[0] < 5:
        return node.glare_type

    # assume it's not linked
    val: str = node.inputs[1].default_value
    return val.capitalize()