feat: layer list system

This commit is contained in:
2024-08-14 14:16:40 +08:00
parent 21e0b85662
commit 9e885865f7
21 changed files with 1451 additions and 825 deletions

View File

@@ -1,15 +1,17 @@
import bpy
import bmesh
from ..nodes import custom_nodes
from ..customnodes.nodes import AddCustomNode
from ..bioxel.io import load_container, save_container
from ..bioxelutils.layer import get_all_layer_objs
from ..bioxelutils.container import (container_to_obj, obj_to_container,
get_container_objs_from_selection)
from ..bioxelutils.node import get_nodes_by_type, move_node_between_nodes, move_node_to_node
from .utils import change_render_setting, get_cache_dir, get_preferences, select_object
from ..bioxelutils.container import container_to_obj, obj_to_container
from ..bioxelutils.utils import (get_container_layer_objs, get_container_obj, get_nodes_by_type,
move_node_between_nodes,
move_node_to_node,
get_all_layer_objs)
from .utils import get_cache_dir, select_object
class SaveContainer(bpy.types.Operator):
@@ -23,19 +25,14 @@ class SaveContainer(bpy.types.Operator):
filename_ext = ".bioxel"
@classmethod
def poll(cls, context):
container_objs = get_container_objs_from_selection()
return len(container_objs) > 0
def execute(self, context):
container_objs = get_container_objs_from_selection()
container_obj = get_container_obj(context.object)
if len(container_objs) == 0:
if container_obj is None:
self.report({"WARNING"}, "Cannot find any bioxel container.")
return {'FINISHED'}
container = obj_to_container(container_objs[0])
container = obj_to_container(container_obj)
save_path = f"{self.filepath.split('.')[0]}.bioxel"
save_container(container, save_path, overwrite=True)
@@ -82,20 +79,13 @@ class LoadContainer(bpy.types.Operator):
class PickObject():
bl_options = {'UNDO'}
@classmethod
def poll(cls, context):
container_objs = get_container_objs_from_selection()
return len(container_objs) > 0
def execute(self, context):
container_objs = get_container_objs_from_selection()
container_obj = get_container_obj(context.object)
if len(container_objs) == 0:
if container_obj is None:
self.report({"WARNING"}, "Cannot find any bioxel container.")
return {'FINISHED'}
container_obj = container_objs[0]
bpy.ops.mesh.primitive_cube_add(
size=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
obj = bpy.context.active_object
@@ -124,6 +114,7 @@ class PickMesh(bpy.types.Operator, PickObject):
bl_idname = "bioxelnodes.pick_mesh"
bl_label = "Pick Mesh"
bl_description = "Pick Container Mesh"
bl_icon = "OUTLINER_OB_MESH"
object_type = "Mesh"
@@ -131,6 +122,7 @@ class PickVolume(bpy.types.Operator, PickObject):
bl_idname = "bioxelnodes.pick_volume"
bl_label = "Pick Volume"
bl_description = "Pick Container Volume"
bl_icon = "OUTLINER_OB_VOLUME"
object_type = "Volume"
@@ -138,45 +130,34 @@ class PickBboxWire(bpy.types.Operator, PickObject):
bl_idname = "bioxelnodes.pick_bbox_wire"
bl_label = "Pick Bbox Wire"
bl_description = "Pick Container Bbox Wire"
bl_icon = "MESH_CUBE"
object_type = "BboxWire"
class AddCutter():
bl_options = {'UNDO'}
@classmethod
def poll(cls, context):
container_objs = get_container_objs_from_selection()
return len(container_objs) > 0
def execute(self, context):
container_objs = get_container_objs_from_selection()
container_obj = get_container_obj(context.object)
if len(container_objs) == 0:
if container_obj is None:
self.report({"WARNING"}, "Cannot find any bioxel container.")
return {'FINISHED'}
container_obj = container_objs[0]
if self.object_type == "plane":
node_type = "BioxelNodes_PlaneObjectCutter"
# TODO: do not use operator to create obj
if self.cutter_type == "plane":
bpy.ops.mesh.primitive_plane_add(
size=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
elif self.object_type == "cylinder":
node_type = "BioxelNodes_CylinderObjectCutter"
elif self.cutter_type == "cylinder":
bpy.ops.mesh.primitive_cylinder_add(
radius=1, depth=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
bpy.context.object.rotation_euler[0] = container_obj.rotation_euler[0]
elif self.object_type == "cube":
node_type = "BioxelNodes_CubeObjectCutter"
elif self.cutter_type == "cube":
bpy.ops.mesh.primitive_cube_add(
size=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
elif self.object_type == "sphere":
node_type = "BioxelNodes_SphereObjectCutter"
elif self.cutter_type == "sphere":
bpy.ops.mesh.primitive_ico_sphere_add(
radius=1, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
elif self.object_type == "pie":
node_type = "BioxelNodes_PieObjectCutter"
elif self.cutter_type == "pie":
# Create mesh
pie_mesh = bpy.data.meshes.new('Pie')
@@ -211,6 +192,7 @@ class AddCutter():
bpy.context.view_layer.objects.active = pie
cutter_obj = bpy.context.active_object
cutter_obj.location = container_obj.location
cutter_obj.visible_camera = False
cutter_obj.visible_diffuse = False
cutter_obj.visible_glossy = False
@@ -220,16 +202,23 @@ class AddCutter():
cutter_obj.hide_render = True
cutter_obj.display_type = 'WIRE'
select_object(container_obj)
modifier = container_obj.modifiers[0]
node_group = modifier.node_group
cutter_node = custom_nodes.add_node(node_group, node_type)
cutter_node.inputs[0].default_value = cutter_obj
cut_nodes = get_nodes_by_type(node_group,
'BioxelNodes_Cut')
output_node = get_nodes_by_type(node_group, 'NodeGroupOutput')[0]
if len(cut_nodes) == 0:
cut_node = custom_nodes.add_node(node_group, 'BioxelNodes_Cut')
cutter_node = custom_nodes.add_node(node_group,
"BioxelNodes_ObjectCutter")
cutter_node.inputs[0].default_value = self.cutter_type.capitalize()
cutter_node.inputs[1].default_value = cutter_obj
cut_node = custom_nodes.add_node(node_group,
'BioxelNodes_Cut')
output_node = get_nodes_by_type(node_group,
'NodeGroupOutput')[0]
if len(output_node.inputs[0].links) == 0:
node_group.links.new(cut_node.outputs[0],
output_node.inputs[0])
@@ -247,44 +236,132 @@ class AddCutter():
cut_node.inputs[1])
move_node_to_node(cutter_node, cut_node, (-300, -300))
select_object(cutter_obj)
else:
move_node_to_node(cutter_node, output_node, (0, -100))
select_object(container_obj)
bpy.ops.bioxelnodes.object_cutter('INVOKE_DEFAULT',
cutter_obj_name=cutter_obj.name,
cutter_type=self.cutter_type.capitalize())
return {'FINISHED'}
class ObjectCutter(bpy.types.Operator, AddCustomNode):
bl_idname = "bioxelnodes.object_cutter"
bl_label = "Object Cutter"
bl_description = "Object Cutter"
bl_icon = "NODE"
bl_options = {'UNDO'}
cutter_obj_name: bpy.props.StringProperty() # type: ignore
cutter_type: bpy.props.StringProperty() # type: ignore
def execute(self, context):
cutter_obj = bpy.data.objects.get(self.cutter_obj_name)
if cutter_obj == None:
self.report({"WARNING"}, "Get no layer.")
return {'FINISHED'}
self.get_node_tree(self.node_type, self.node_link)
prev_context = bpy.context.area.type
bpy.context.area.type = 'NODE_EDITOR'
bpy.ops.node.add_node('INVOKE_DEFAULT',
type='GeometryNodeGroup',
use_transform=True)
bpy.context.area.type = prev_context
node = bpy.context.active_node
self.assign_node_tree(node)
node.show_options = False
node.label = "Object Cutter"
node.inputs[0].default_value = self.cutter_type
node.inputs[1].default_value = cutter_obj
return {"FINISHED"}
def invoke(self, context, event):
self.nodes_file = custom_nodes.nodes_file
self.node_type = "BioxelNodes_ObjectCutter"
return self.execute(context)
class AddPlaneCutter(bpy.types.Operator, AddCutter):
bl_idname = "bioxelnodes.add_plane_cutter"
bl_label = "Add a Plane Cutter"
bl_description = "Add a Plane Cutter to Container"
object_type = "plane"
bl_icon = "MESH_PLANE"
cutter_type = "plane"
class AddCylinderCutter(bpy.types.Operator, AddCutter):
bl_idname = "bioxelnodes.add_cylinder_cutter"
bl_label = "Add a Cylinder Cutter"
bl_description = "Add a Cylinder Cutter to Container"
object_type = "cylinder"
bl_icon = "MESH_CYLINDER"
cutter_type = "cylinder"
class AddCubeCutter(bpy.types.Operator, AddCutter):
bl_idname = "bioxelnodes.add_cube_cutter"
bl_label = "Add a Cube Cutter"
bl_description = "Add a Cube Cutter to Container"
object_type = "cube"
bl_icon = "MESH_CUBE"
cutter_type = "cube"
class AddSphereCutter(bpy.types.Operator, AddCutter):
bl_idname = "bioxelnodes.add_sphere_cutter"
bl_label = "Add a Sphere Cutter"
bl_description = "Add a Sphere Cutter to Container"
object_type = "sphere"
bl_icon = "MESH_UVSPHERE"
cutter_type = "sphere"
class AddPieCutter(bpy.types.Operator, AddCutter):
bl_idname = "bioxelnodes.add_pie_cutter"
bl_label = "Add a Pie Cutter"
bl_description = "Add a Pie Cutter to Container"
object_type = "pie"
bl_icon = "MESH_CONE"
cutter_type = "pie"
class SaveAllLayerCaches(bpy.types.Operator):
bl_idname = "bioxelnodes.save_all_layer_caches"
bl_label = "Save All Layer Caches"
bl_description = "Save Container's caches to directory."
bl_icon = "FILE_TICK"
cache_dir: bpy.props.StringProperty(
name="Cache Directory",
subtype='DIR_PATH',
default="//"
) # type: ignore
def execute(self, context):
container_obj = get_container_obj(context.object)
if container_obj is None:
self.report({"WARNING"}, "Cannot find any bioxel container.")
return {'FINISHED'}
fails = []
for layer_obj in get_container_layer_objs(container_obj):
try:
bpy.ops.bioxelnodes.save_layer_cache('EXEC_DEFAULT',
layer_obj_name=layer_obj.name,
cache_dir=self.cache_dir)
except:
fails.append(layer_obj)
if len(fails) == 0:
self.report({"INFO"}, f"Successfully saved bioxel layers.")
else:
self.report(
{"WARNING"}, f"{','.join([layer.name for layer in fails])} fail to save.")
return {'FINISHED'}
def invoke(self, context, event):
context.window_manager.invoke_props_dialog(self,
width=500)
return {'RUNNING_MODAL'}