
class GroupControllerNode(bpy.types.Node):
bl_idname = 'group_controller_type'
bl_label = 'Group Controller Node'
bl_icon = 'STICKY_UVS_LOC'
bl_width_default = 200
# Assigned by group_info_updater on str_selected_light property.
str_group_id: StringProperty(default="1")
str_group_channels: StringProperty(default="")
str_group_label: StringProperty(default="")
# OSC argument templates for properties specific to the fixture type, not scene. For example, strobe, not intensity.
str_enable_strobe_argument: StringProperty(default="# Strobe_Mode 127 Enter", description="Add # for group ID")
str_disable_strobe_argument: StringProperty(default="# Strobe_Mode 76 Enter", description="Add # for group ID")
str_enable_gobo_speed_argument: StringProperty(default="# Gobo_Mode 191 Enter", description="Add # for group ID")
str_disable_gobo_speed_argument: StringProperty(default="# Gobo_Mode 63 Enter", description="Add # for group ID")
str_gobo_id_argument: StringProperty(default="# Gobo_Select $ Enter", description="Add # for group ID and $ for value")
str_gobo_speed_value_argument: StringProperty(default="# Gobo_Index/Speed at $ Enter", description="Add $ for animation data and # for fixture/group ID")
str_enable_misc_effect_argument: StringProperty(default="# Gobo_Wheel_Mode 213 Enter", description="Add # for group ID")
str_disable_misc_effect_argument: StringProperty(default="# Gobo_Wheel_Mode 213 Enter", description="Add # for group ID")
str_enable_prism_argument: StringProperty(default="# Beam_Fx_Select 02 Enter", description="Add # for group ID")
str_disable_prism_argument: StringProperty(default="# Beam_Fx_Select 01 Enter", description="Add # for group ID")
# Min/max values mapped from 0-100 scale inside the harmonizer since we cannot live-update prop min/maxes.
# This provides user full use of the slider at all times.
pan_min: bpy.props.IntProperty(default=-270, description="Minimum value for pan")
pan_max: bpy.props.IntProperty(default=270, description="Maximum value for pan")
tilt_min: bpy.props.IntProperty(default=-135, description="Minimum value for tilt")
tilt_max: bpy.props.IntProperty(default=135, description="Maximum value for tilt")
strobe_min: bpy.props.IntProperty(default=0, description="Minimum value for strobe")
strobe_max: bpy.props.IntProperty(default=10, description="Maximum value for strobe")
zoom_min: bpy.props.IntProperty(default=1, description="Minimum value for zoom")
zoom_max: bpy.props.IntProperty(default=100, description="Maximum value for zoom")
iris_min: bpy.props.IntProperty(default=0, description="Minimum value for iris")
iris_max: bpy.props.IntProperty(default=100, description="Maximum value for iris")
edge_min: bpy.props.IntProperty(default=0, description="Minimum value for edge")
edge_max: bpy.props.IntProperty(default=100, description="Maximum value for edge")
speed_min: bpy.props.IntProperty(default=-200, description="Minimum value for speed")
speed_max: bpy.props.IntProperty(default=200, description="Maximum value for speed")
changer_speed_min: IntProperty(default=0, description="Minimum value for changer speed")
changer_speed_max: IntProperty(default=0, description="Maximum value for changer speed")
# Selected group and color profile enumerators.
str_selected_light: EnumProperty(
name="Selected Light",
description="Choose a light object",
items=lamp_objects,
update=group_info_updater
)
color_profile_enum: EnumProperty(
name="Color Profile",
description="Choose a color profile for the group",
items=color_profiles,
)
# User-accessible property definitions.
influence: IntProperty(default=1, min=1, max=10, description="How many votes this controller has when there are conflicts", options={'ANIMATABLE'})
float_intensity: FloatProperty(default=0, min=0, max=100, description="Intensity value", options={'ANIMATABLE'}, update=group_intensity_updater)
float_vec_color: FloatVectorProperty(
name="",
subtype='COLOR',
size=3,
default=(1.0, 1.0, 1.0),
min=0.0,
max=1.0,
description="Color value",
update=group_color_updater
)
float_diffusion: FloatProperty(default=0, min=0, max=100, description="Diffusion value", options={'ANIMATABLE'}, update=group_diffusion_updater)
float_pan: bpy.props.FloatProperty(default=0, min=-100, max=100, description="Pan value", options={'ANIMATABLE'}, update=group_pan_updater)
float_tilt: FloatProperty(default=0, min=-100, max=100, description="Tilt value", options={'ANIMATABLE'}, update=group_tilt_updater)
float_strobe: FloatProperty(default=0, min=0, max=100, description="Strobe value", options={'ANIMATABLE'}, update=group_strobe_updater)
float_zoom: FloatProperty(default=0, min=0, max=100, description="Zoom value", options={'ANIMATABLE'}, update=group_zoom_updater)
float_iris: FloatProperty(default=0, min=0, max=100, description="Iris value", options={'ANIMATABLE'}, update=group_iris_updater)
float_edge: FloatProperty(default=0, min=0, max=100, description="Edge value", options={'ANIMATABLE'}, update=group_edge_updater)
int_gobo_id: IntProperty(default=1, min=0, max=20, description="Gobo selection", options={'ANIMATABLE'}, update=group_gobo_id_updater)
float_gobo_speed: FloatProperty(default=0, min=-100, max=100, description="Rotation of individual gobo speed", options={'ANIMATABLE'}, update=group_speed_updater)
float_disc_speed: FloatProperty(default=0, min=-100, max=100, description="Rotation of gobo disc/wheel speed", options={'ANIMATABLE'})
int_prism: IntProperty(default=0, min=0, max=1, description="Prism value. 1 is on, 0 is off", options={'ANIMATABLE'}, update=group_prism_updater)
# Checkers for aborting redundant updates from frame_change_pre handler.
float_influence_checker: FloatProperty(default=0, description="How much influence this controller has", options={'ANIMATABLE'})
float_intensity_checker: FloatProperty(default=0, min=0, max=100, description="Intensity value", options={'ANIMATABLE'})
float_vec_color_checker: FloatVectorProperty(name="", subtype='COLOR', size=3, default=(1.0, 1.0, 1.0))
float_pan_checker: FloatProperty(default=0,)
float_tilt_checker: FloatProperty(default=0)
float_diffusion_checker: FloatProperty(default=0)
float_strobe_checker: FloatProperty(default=0)
float_zoom_checker: FloatProperty(default=0)
float_iris_checker: FloatProperty(default=0)
float_edge_checker: FloatProperty(default=0)
gobo_id_checker: FloatProperty(default=0)
float_speed_checker: FloatProperty(default=0)
prism_checker: FloatProperty(default=0)
# Fan Center effect booleans.
use_fan_center_intensity: BoolProperty(default=False, description="Use Fan Center effect")
use_fan_center_tilt: BoolProperty(default=False, description="Use Fan Center effect")
use_fan_center_pan: BoolProperty(default=False, description="Use Fan Center effect")
use_fan_center_diffusion: BoolProperty(default=False, description="Use Fan Center effect")
use_fan_center_strobe: BoolProperty(default=False, description="Use Fan Center effect")
use_fan_center_zoom: BoolProperty(default=False, description="Use Fan Center effect")
use_fan_center_iris: BoolProperty(default=False, description="Use Fan Center effect")
use_fan_center_edge: BoolProperty(default=False, description="Use Fan Center effect")
use_fan_center_speed: BoolProperty(default=False, description="Use Fan Center effect")
# Toggles for turning off visibility to unneeded parameters.
influence_is_on: BoolProperty(default=False, description="Influence is enabled when checked")
intensity_is_on: BoolProperty(default=False, description="Intensity is enabled when checked")
pan_tilt_is_on: BoolProperty(default=False, description="Pan/Tilt is enabled when checked")
color_is_on: BoolProperty(default=False, description="Color is enabled when checked")
diffusion_is_on: BoolProperty(default=False, description="Diffusion is enabled when checked")
strobe_is_on: BoolProperty(default=False, description="Strobe is enabled when checked")
zoom_is_on: BoolProperty(default=False, description="Zoom is enabled when checked")
iris_is_on: BoolProperty(default=False, description="Iris is enabled when checked")
edge_is_on: BoolProperty(default=False, description="Edge is enabled when checked")
gobo_id_is_on: BoolProperty(default=False, description="Gobo ID is enabled when checked")
prism_is_on: BoolProperty(default=False, description="Prism is enabled when checked")
def init(self, context):
self.inputs.new('GroupInputType', "Driver Input")
self.inputs.new('GroupInputType', "Driver Input")
self.outputs.new('FlashOutType', "Flash")
return
def draw_buttons(self, context, layout):
if self.influence_is_on:
row = layout.row(align=True)
row.prop(self, "influence", slider=True, text="Influence:")
layout.separator()
# This was originally added to avoid using depsgraph_update handler to reduce traffic, may be cut from final.
active_influencer = bpy.data.objects.get(self.str_selected_light)
if active_influencer is not None and active_influencer.select_get() and active_influencer.type == 'MESH':
if active_influencer.is_influencer:
row = layout.row()
row.label(text="Influencer Location:")
row = layout.row(align=True)
row.prop(self, "influencer_x_location", toggle=True, text="X")
row = layout.row(align=True)
row.prop(self, "influencer_y_location", toggle=True, text="Y")
row = layout.row(align=True)
row.prop(self, "influencer_z_location", toggle=True, text="Z")
layout.separator()
layout.separator()
row = layout.row(align=True)
## Use of row.alert logic here is probably redundant per existing Blender UI rules
if not self.str_selected_light:
row.alert = 1
row.prop(self, "str_selected_light", text="", icon_only=True, icon='LIGHT')
row.alert = 0
# Must send identity info to some operators since buttons can be pressed on non-active nodes
op_home = row.operator("node.home_group", icon='HOME', text="")
op_home.node_name = self.name
op_update = row.operator("node.update_group", icon='FILE_REFRESH', text="")
op_update.node_name = self.name
row.prop(self, "float_intensity", slider=True, text="Intensity:")
# All strobe controls on a button/popup to avoid putting it on its own row.
if self.strobe_is_on:
row_one = row.column(align=True)
row_one.scale_x = 1
op = row_one.operator("my.view_strobe_props", icon='OUTLINER_OB_LIGHTPROBE', text="")
op.node_name = self.name
if self.color_is_on:
sub = row.column(align=True)
sub.scale_x = 0.3
sub.prop(self, "float_vec_color", text="")
sub_two = row.column(align=True)
# Do not allow students/volunteers to mess up the color profile setting.
if not context.scene.scene_props.school_mode_enabled:
sub_two.scale_x = 0.8
sub_two.prop(self, "color_profile_enum", text="", icon='COLOR', icon_only=True)
if self.pan_tilt_is_on:
row = layout.row(align=True)
op = row.operator("my.view_pan_tilt_props", icon='ORIENTATION_GIMBAL', text="")
op.node_name = self.name
## Need to switch to the blue color, not the red.
if self.use_fan_center_pan:
row.alert = 1
row.prop(self, "use_fan_center_pan", text="", icon='PARTICLES')
row.alert = 0
row.prop(self, "float_pan", text="Pan", slider=True)
if self.use_fan_center_tilt:
row.alert = 1
row.prop(self, "use_fan_center_tilt", text="", icon='PARTICLES')
row.alert = 0
row.prop(self, "float_tilt", text="Tilt", slider=True)
if self.zoom_is_on or self.iris_is_on:
row = layout.row(align=True)
op = row.operator("my.view_zoom_iris_props", text="", icon='LINCURVE')
op.node_name = self.name
if self.zoom_is_on:
if self.use_fan_center_zoom:
row.alert = 1
row.prop(self, "use_fan_center_zoom", text="", icon='PARTICLES')
row.alert = 0
row.prop(self, "float_zoom", slider=True, text="Zoom:")
if self.iris_is_on:
if self.use_fan_center_iris:
row.alert = 1
row.prop(self, "use_fan_center_iris", text="", icon='PARTICLES')
row.alert = 0
row.prop(self, "float_iris", slider=True, text="Iris:")
if self.edge_is_on or self.diffusion_is_on:
row = layout.row(align=True)
op = row.operator("my.view_edge_diffusion_props", text="", icon='SELECT_SET')
op.node_name = self.name
if self.edge_is_on:
if self.use_fan_center_zoom:
row.alert = 1
row.prop(self, "use_fan_center_edge", text="", icon='PARTICLES')
row.alert = 0
row.prop(self, "float_edge", slider=True, text="Edge:")
if self.diffusion_is_on:
if self.use_fan_center_diffusion:
row.alert = 1
row.prop(self, "use_fan_center_diffusion", text="", icon='PARTICLES')
row.alert = 0
row.prop(self, "float_diffusion", slider=True, text="Diffusion:")
if self.gobo_id_is_on:
row = layout.row(align=True)
op = row.operator("my.view_gobo_props", text="", icon='POINTCLOUD_DATA')
op.node_name = self.name
row.prop(self, "int_gobo_id", text="Gobo:")
row.prop(self, "float_gobo_speed", slider=True, text="Speed:")
row.prop(self, "int_prism", slider=True, text="Prism:")
I’ve narrowed down the crashing issue to the script that comes from (currently at about 3,000 lines total out of a ~20,000 line project). I think it has something to do with my really elaborate “harmonizer” system. It’s there to harmonize conflicting control requests from multiple different controllers trying to control the same lighting fixture differently. Any parameter change might be handled by 10-15 different functions before it gets out of Blender. I’m going to be working on massively simplifying that system even though getting that system to work in the first place was a massive victory earlier in the project. But it needs to be simpler and smarter, and something about it is crashing Blender. My hope is I just need to rephrase one line or one type of line somewhere.