Public Access
2
0
Files
stocker_helper/__init__.py
T

167 lines
5.6 KiB
Python

import bpy
# Import the logic from previous phases
from .scripts import phase2_geometry as logic
bl_info = {
"name": "Stocker Helper",
"author": "Gary Ritchie",
"version": (0, 5, 0),
"blender": (4, 0, 0),
"location": "View3D > Sidebar > Stocker",
"description": "Creates boundary object with Stocker Geometry Nodes assets (sold separately.)",
"category": "Object",
}
def find_and_append_node_group(name):
"""Search asset libraries for a node group and append it if found."""
import os
if name in bpy.data.node_groups:
return bpy.data.node_groups[name]
# Get libraries, prioritizing those starting with 'stocker' (lowercase)
libraries = list(bpy.context.preferences.filepaths.asset_libraries)
libraries.sort(key=lambda l: not os.path.basename(l.path).lower().startswith("stocker"))
for lib in libraries:
if not lib.path or not os.path.exists(lib.path):
continue
print(f"Stocker: Searching library {lib.path} for {name}...")
for root, dirs, files in os.walk(lib.path):
for file in files:
if file.endswith(".blend"):
path = os.path.join(root, file)
try:
with bpy.data.libraries.load(path) as (data_from, data_to):
if name in data_from.node_groups:
data_to.node_groups = [name]
if name in bpy.data.node_groups:
print(f"Stocker: Successfully appended {name} from {path}")
return bpy.data.node_groups[name]
except:
continue
return None
class STOCKER_PT_panel(bpy.types.Panel):
bl_label = "Stocker Helper"
bl_idname = "STOCKER_PT_panel"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = 'Stocker'
def draw(self, context):
layout = self.layout
col = layout.column(align=True)
# New Height Buffer slider
col.prop(context.scene, "stocker_height_buffer", text="Height Buffer (%)")
col.separator()
op_grid = col.operator("object.stocker_setup", text="Grid Boundary")
op_grid.mode = 'GRID'
op_grid.height_buffer = context.scene.stocker_height_buffer
op_circle = col.operator("object.stocker_setup", text="Circle Boundary")
op_circle.mode = 'CIRCLE'
op_circle.height_buffer = context.scene.stocker_height_buffer
class STOCKER_OT_setup(bpy.types.Operator):
bl_idname = "object.stocker_setup"
bl_label = "Stocker Helper"
bl_description = "Generate a boundary cube for the selected objects"
bl_options = {'REGISTER', 'UNDO'}
mode: bpy.props.EnumProperty(
name="Packing Mode",
description="Select the geometry nodes template to apply",
items=[
('GRID', "Grid Pack", "Use the Grid Pack template"),
('CIRCLE', "Circle Pack", "Use the Circle Pack template"),
],
default='GRID'
)
height_buffer: bpy.props.FloatProperty(
name="Height Buffer",
description="Percentage to add to the Z height (0.1 = 10%)",
default=0.1,
min=0.0,
max=2.0
)
def execute(self, context):
# 1. Get selected objects
selected_objs = context.selected_objects
# 2. Run logic from previous phases
bounds = logic.calculate_global_bounds(selected_objs, parent=selected_objs[0])
if not bounds:
self.report({'ERROR'}, "No valid mesh objects selected.")
return {'CANCELLED'}
# Apply the Z height buffer
if self.height_buffer > 0:
height_add = bounds['size'].z * self.height_buffer
bounds['size'].z += height_add
bounds['max'].z += height_add
# 3. Create the cube (parent to selected for tracking)
new_obj = logic.create_aligned_boundary_cube(bounds, parent=selected_objs[0], mode=self.mode)
if not new_obj:
self.report({'ERROR'}, "Failed to create boundary cube.")
return {'CANCELLED'}
# 4. Modifier Injection
group_name = "grid_pack" if self.mode == 'GRID' else "circle_pack"
mod_name = "grid_pack" if self.mode == 'GRID' else "circle_pack"
# Try to get or fetch the node group with visual feedback
context.window.cursor_modal_set('WAIT')
self.report({'INFO'}, f"Searching asset libraries for {group_name}...")
try:
node_group = find_and_append_node_group(group_name)
finally:
context.window.cursor_modal_restore()
if not node_group:
self.report({'WARNING'}, f"Node Group '{group_name}' not found in file or Stocker Asset Libraries.")
return {'FINISHED'}
mod = new_obj.modifiers.new(name=mod_name, type='NODES')
mod.node_group = node_group
self.report({'INFO'}, f"Stocker setup complete using {self.mode} mode.")
return {'FINISHED'}
@classmethod
def poll(cls, context):
return context.selected_objects
classes = (
STOCKER_PT_panel,
STOCKER_OT_setup,
)
def register():
bpy.types.Scene.stocker_height_buffer = bpy.props.FloatProperty(
name="Stocker Height Buffer",
description="Default height buffer for new boundaries",
default=0.1,
min=0.0,
max=2.0
)
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)
del bpy.types.Scene.stocker_height_buffer
if __name__ == "__main__":
register()