298 lines
11 KiB
Python
298 lines
11 KiB
Python
from pathlib import Path
|
|
import bpy
|
|
|
|
from .operators.utils import get_layer_item_label
|
|
from .bioxelutils.utils import (get_container_obj,
|
|
get_container_objs_from_selection,
|
|
get_container_layer_objs,
|
|
get_layer_prop_value)
|
|
from .operators.layer import (FetchLayerMenu, FetchLayer,
|
|
RemoveLayer, RemoveMissingLayers, RenameLayer, ResampleScalar, SaveLayerCache,
|
|
SignScalar, CombineLabels,
|
|
FillByLabel, FillByThreshold, FillByRange, get_selected_objs_in_node_tree)
|
|
from .operators.container import (SaveAllLayerCaches, SaveContainer, LoadContainer,
|
|
AddPieCutter, AddPlaneCutter,
|
|
AddCylinderCutter, AddCubeCutter, AddSphereCutter,
|
|
PickBboxWire, PickMesh, PickVolume)
|
|
from .operators.io import (ImportAsLabel, ImportAsScalar, ImportAsColor)
|
|
from .operators.misc import (CleanAllCaches,
|
|
ReLinkNodes, RenderSettingPreset, SaveStagedData)
|
|
|
|
|
|
class PickFromContainerMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_PICK"
|
|
bl_label = "Pick from Container"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(PickMesh.bl_idname)
|
|
layout.operator(PickVolume.bl_idname)
|
|
layout.operator(PickBboxWire.bl_idname)
|
|
|
|
|
|
class AddCutterMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_CUTTERS"
|
|
bl_label = "Add a Object Cutter"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(AddPlaneCutter.bl_idname, text="Plane Cutter")
|
|
layout.operator(AddCylinderCutter.bl_idname, text="Cylinder Cutter")
|
|
layout.operator(AddCubeCutter.bl_idname, text="Cube Cutter")
|
|
layout.operator(AddSphereCutter.bl_idname, text="Sphere Cutter")
|
|
layout.operator(AddPieCutter.bl_idname, text="Pie Cutter")
|
|
|
|
|
|
class ImportLayerMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_IMPORTLAYER"
|
|
bl_label = "Import Volumetric Data (Init)"
|
|
bl_icon = "FILE_NEW"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(ImportAsScalar.bl_idname,
|
|
text="as Scalar")
|
|
layout.operator(ImportAsLabel.bl_idname,
|
|
text="as Label")
|
|
layout.operator(ImportAsColor.bl_idname,
|
|
text="as Color")
|
|
|
|
|
|
class AddLayerMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_ADDLAYER"
|
|
bl_label = "Import Volumetric Data (Add to)"
|
|
bl_icon = "FILE_NEW"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(ImportAsScalar.bl_idname,
|
|
text="as Scalar")
|
|
layout.operator(ImportAsLabel.bl_idname,
|
|
text="as Label")
|
|
layout.operator(ImportAsColor.bl_idname,
|
|
text="as Color")
|
|
|
|
|
|
class ModifyLayerMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_MODIFYLAYER"
|
|
bl_label = "Modify Layer"
|
|
bl_icon = "FILE_NEW"
|
|
|
|
def draw(self, context):
|
|
layer_objs = get_selected_objs_in_node_tree(context)
|
|
if len(layer_objs) > 0:
|
|
active_obj_name = layer_objs[0].name
|
|
else:
|
|
active_obj_name = ""
|
|
|
|
layout = self.layout
|
|
op = layout.operator(ResampleScalar.bl_idname,
|
|
icon=ResampleScalar.bl_icon)
|
|
op.layer_obj_name = active_obj_name
|
|
op = layout.operator(SignScalar.bl_idname,
|
|
icon=SignScalar.bl_icon)
|
|
op.layer_obj_name = active_obj_name
|
|
op = layout.operator(FillByThreshold.bl_idname,
|
|
icon=FillByThreshold.bl_icon)
|
|
op.layer_obj_name = active_obj_name
|
|
op = layout.operator(FillByRange.bl_idname,
|
|
icon=FillByRange.bl_icon)
|
|
op.layer_obj_name = active_obj_name
|
|
op = layout.operator(FillByLabel.bl_idname,
|
|
icon=FillByLabel.bl_icon)
|
|
op.layer_obj_name = active_obj_name
|
|
op = layout.operator(CombineLabels.bl_idname,
|
|
icon=CombineLabels.bl_icon)
|
|
op.layer_obj_name = active_obj_name
|
|
|
|
|
|
class RenderSettingMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_RENDER"
|
|
bl_label = "Render Setting Presets"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
for k, v in RenderSettingPreset.PRESETS.items():
|
|
op = layout.operator(RenderSettingPreset.bl_idname,
|
|
text=v)
|
|
op.preset = k
|
|
|
|
|
|
class BioxelNodesTopbarMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_TOPBAR"
|
|
bl_label = "Bioxel Nodes"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
layout.menu(ImportLayerMenu.bl_idname,
|
|
icon=ImportLayerMenu.bl_icon)
|
|
layout.operator(LoadContainer.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.operator(SaveStagedData.bl_idname)
|
|
layout.operator(ReLinkNodes.bl_idname)
|
|
layout.operator(CleanAllCaches.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.menu(RenderSettingMenu.bl_idname)
|
|
|
|
|
|
def TOPBAR(self, context):
|
|
layout = self.layout
|
|
layout.menu(BioxelNodesTopbarMenu.bl_idname)
|
|
|
|
|
|
class BioxelNodesNodeMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_NODE"
|
|
bl_label = "Bioxel Nodes"
|
|
bl_icon = "FILE_VOLUME"
|
|
|
|
def draw(self, context):
|
|
layer_objs = get_selected_objs_in_node_tree(context)
|
|
if len(layer_objs) > 0:
|
|
active_obj_name = layer_objs[0].name
|
|
else:
|
|
active_obj_name = ""
|
|
|
|
layout = self.layout
|
|
|
|
layout.menu(AddLayerMenu.bl_idname,
|
|
icon=AddLayerMenu.bl_icon)
|
|
|
|
layout.operator(RemoveMissingLayers.bl_idname,
|
|
icon=RemoveMissingLayers.bl_icon)
|
|
|
|
layout.separator()
|
|
layout.operator(SaveContainer.bl_idname)
|
|
layout.menu(AddCutterMenu.bl_idname)
|
|
layout.menu(PickFromContainerMenu.bl_idname)
|
|
layout.operator(SaveAllLayerCaches.bl_idname,
|
|
icon=SaveAllLayerCaches.bl_icon)
|
|
|
|
layout.separator()
|
|
layout.menu(FetchLayerMenu.bl_idname)
|
|
op = layout.operator(SaveLayerCache.bl_idname,
|
|
icon=SaveLayerCache.bl_icon)
|
|
op.layer_obj_name = active_obj_name
|
|
op = layout.operator(RenameLayer.bl_idname,
|
|
icon=RenameLayer.bl_icon)
|
|
op.layer_obj_name = active_obj_name
|
|
|
|
op = layout.operator(RemoveLayer.bl_idname,
|
|
icon=RemoveLayer.bl_icon)
|
|
op.layer_obj_name = active_obj_name
|
|
|
|
layout.separator()
|
|
layout.menu(ModifyLayerMenu.bl_idname)
|
|
|
|
|
|
def NODE(self, context):
|
|
container_obj = context.object
|
|
is_geo_nodes = context.area.ui_type == "GeometryNodeTree"
|
|
is_container = get_container_obj(container_obj)
|
|
|
|
if not is_geo_nodes or not is_container:
|
|
return
|
|
|
|
layout = self.layout
|
|
layout.separator()
|
|
layout.menu(BioxelNodesNodeMenu.bl_idname)
|
|
|
|
|
|
def NODE_PT(self, context):
|
|
container_obj = context.object
|
|
is_geo_nodes = context.area.ui_type == "GeometryNodeTree"
|
|
is_container = get_container_obj(container_obj)
|
|
self.bl_label = "Group"
|
|
|
|
if not is_geo_nodes or not is_container:
|
|
return
|
|
|
|
if container_obj.modifiers[0].node_group != context.space_data.edit_tree:
|
|
return
|
|
|
|
self.bl_label = "Bioxel Nodes"
|
|
|
|
layer_list_UL = bpy.context.window_manager.bioxelnodes_layer_list_UL
|
|
layer_list = layer_list_UL.layer_list
|
|
layer_list_active = layer_list_UL.layer_list_active
|
|
layer_list.clear()
|
|
|
|
for layer_obj in get_container_layer_objs(container_obj):
|
|
layer_item = layer_list.add()
|
|
layer_item.label = get_layer_item_label(context, layer_obj)
|
|
layer_item.obj_name = layer_obj.name
|
|
layer_item.info_text = "\n".join([f"{prop}: {get_layer_prop_value(layer_obj, prop)}"
|
|
for prop in ["kind", "bioxel_size", "shape", "min", "max", ]])
|
|
|
|
if len(layer_list) > 0 and layer_list_active != -1 and layer_list_active < len(layer_list):
|
|
active_obj_name = layer_list[layer_list_active].obj_name
|
|
else:
|
|
active_obj_name = ""
|
|
|
|
layout = self.layout
|
|
layout.label(text="Layer List")
|
|
split = layout.row()
|
|
split.template_list(listtype_name="BIOXELNODES_UL_layer_list",
|
|
list_id="layer_list",
|
|
dataptr=layer_list_UL,
|
|
propname="layer_list",
|
|
active_dataptr=layer_list_UL,
|
|
active_propname="layer_list_active",
|
|
item_dyntip_propname="info_text",
|
|
rows=20)
|
|
|
|
sidebar = split.column(align=True)
|
|
sidebar.menu(AddLayerMenu.bl_idname,
|
|
icon=AddLayerMenu.bl_icon, text="")
|
|
|
|
sidebar.operator(RemoveMissingLayers.bl_idname,
|
|
icon=RemoveMissingLayers.bl_icon, text="")
|
|
|
|
sidebar.separator()
|
|
op = sidebar.operator(FetchLayer.bl_idname,
|
|
icon=FetchLayer.bl_icon, text="")
|
|
op.layer_obj_name = active_obj_name
|
|
op = sidebar.operator(SaveLayerCache.bl_idname,
|
|
icon=SaveLayerCache.bl_icon, text="")
|
|
op.layer_obj_name = active_obj_name
|
|
op = sidebar.operator(RenameLayer.bl_idname,
|
|
icon=RenameLayer.bl_icon, text="")
|
|
op.layer_obj_name = active_obj_name
|
|
op = sidebar.operator(RemoveLayer.bl_idname,
|
|
icon=RemoveLayer.bl_icon, text="")
|
|
op.layer_obj_name = active_obj_name
|
|
|
|
sidebar.separator()
|
|
op = sidebar.operator(ResampleScalar.bl_idname,
|
|
icon=ResampleScalar.bl_icon, text="")
|
|
op.layer_obj_name = active_obj_name
|
|
op = sidebar.operator(SignScalar.bl_idname,
|
|
icon=SignScalar.bl_icon, text="")
|
|
op.layer_obj_name = active_obj_name
|
|
op = sidebar.operator(FillByThreshold.bl_idname,
|
|
icon=FillByThreshold.bl_icon, text="")
|
|
op.layer_obj_name = active_obj_name
|
|
op = sidebar.operator(FillByRange.bl_idname,
|
|
icon=FillByRange.bl_icon, text="")
|
|
op.layer_obj_name = active_obj_name
|
|
op = sidebar.operator(FillByLabel.bl_idname,
|
|
icon=FillByLabel.bl_icon, text="")
|
|
op.layer_obj_name = active_obj_name
|
|
|
|
sidebar.separator()
|
|
layout.separator()
|
|
|
|
|
|
def add():
|
|
bpy.types.NODE_PT_node_tree_properties.prepend(NODE_PT)
|
|
bpy.types.TOPBAR_MT_editor_menus.append(TOPBAR)
|
|
bpy.types.NODE_MT_editor_menus.append(NODE)
|
|
|
|
|
|
def remove():
|
|
bpy.types.NODE_PT_node_tree_properties.remove(NODE_PT)
|
|
bpy.types.TOPBAR_MT_editor_menus.remove(TOPBAR)
|
|
bpy.types.NODE_MT_editor_menus.remove(NODE)
|