fix: contrast formulation cause leak of high value fix: empty series_id cause fail to read chore: restructure folder chore!: change layer vars BREAKING CHANGE: not support 4.1 any more
284 lines
10 KiB
Python
284 lines
10 KiB
Python
import bpy
|
|
|
|
import bmesh
|
|
|
|
from ..nodes import custom_nodes
|
|
from ..bioxel.io import load_container, save_container
|
|
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 get_cache_dir, select_object
|
|
|
|
|
|
class SaveContainer(bpy.types.Operator):
|
|
bl_idname = "bioxelnodes.save_container"
|
|
bl_label = "Save Container (.bioxel) (BETA)"
|
|
bl_description = "Clean all caches saved in temp"
|
|
|
|
filepath: bpy.props.StringProperty(
|
|
subtype="FILE_PATH"
|
|
) # type: ignore
|
|
|
|
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()
|
|
|
|
if len(container_objs) == 0:
|
|
self.report({"WARNING"}, "Cannot find any bioxel container.")
|
|
return {'FINISHED'}
|
|
|
|
container = obj_to_container(container_objs[0])
|
|
save_path = f"{self.filepath.split('.')[0]}.bioxel"
|
|
save_container(container, save_path, overwrite=True)
|
|
|
|
self.report({"INFO"}, f"Successfully save to {save_path}")
|
|
return {'FINISHED'}
|
|
|
|
def invoke(self, context, event):
|
|
context.window_manager.fileselect_add(self)
|
|
return {'RUNNING_MODAL'}
|
|
|
|
|
|
class LoadContainer(bpy.types.Operator):
|
|
bl_idname = "bioxelnodes.load_container"
|
|
bl_label = "Load Container (.bioxel) (BETA)"
|
|
bl_description = "Clean all caches saved in temp"
|
|
|
|
filepath: bpy.props.StringProperty(
|
|
subtype="FILE_PATH"
|
|
) # type: ignore
|
|
|
|
filename_ext = ".bioxel"
|
|
|
|
def execute(self, context):
|
|
load_path = self.filepath
|
|
container = load_container(self.filepath)
|
|
container_obj = container_to_obj(container,
|
|
scene_scale=0.01,
|
|
cache_dir=get_cache_dir(context))
|
|
select_object(container_obj)
|
|
|
|
self.report({"INFO"}, f"Successfully load {load_path}")
|
|
return {'FINISHED'}
|
|
|
|
def invoke(self, context, event):
|
|
context.window_manager.fileselect_add(self)
|
|
return {'RUNNING_MODAL'}
|
|
|
|
|
|
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()
|
|
|
|
if len(container_objs) == 0:
|
|
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
|
|
|
|
obj.name = f"{self.object_type}_{container_obj.name}"
|
|
|
|
bpy.ops.node.new_geometry_nodes_modifier()
|
|
modifier = obj.modifiers[0]
|
|
node_group = modifier.node_group
|
|
|
|
output_node = get_nodes_by_type(node_group, 'NodeGroupOutput')[0]
|
|
pick_mesh_node = custom_nodes.add_node(node_group,
|
|
f"BioxelNodes_Pick{self.object_type}")
|
|
|
|
pick_mesh_node.inputs[0].default_value = container_obj
|
|
node_group.links.new(pick_mesh_node.outputs[0], output_node.inputs[0])
|
|
|
|
select_object(obj)
|
|
|
|
self.report({"INFO"}, f"Successfully picked")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class PickMesh(bpy.types.Operator, PickObject):
|
|
bl_idname = "bioxelnodes.pick_mesh"
|
|
bl_label = "Pick Mesh"
|
|
bl_description = "Pick Container Mesh"
|
|
object_type = "Mesh"
|
|
|
|
|
|
class PickVolume(bpy.types.Operator, PickObject):
|
|
bl_idname = "bioxelnodes.pick_volume"
|
|
bl_label = "Pick Volume"
|
|
bl_description = "Pick Container Volume"
|
|
object_type = "Volume"
|
|
|
|
|
|
class PickBboxWire(bpy.types.Operator, PickObject):
|
|
bl_idname = "bioxelnodes.pick_bbox_wire"
|
|
bl_label = "Pick Bbox Wire"
|
|
bl_description = "Pick Container Bbox Wire"
|
|
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()
|
|
|
|
if len(container_objs) == 0:
|
|
self.report({"WARNING"}, "Cannot find any bioxel container.")
|
|
return {'FINISHED'}
|
|
|
|
container_obj = container_objs[0]
|
|
|
|
if self.object_type == "plane":
|
|
node_type = "BioxelNodes_PlaneObjectCutter"
|
|
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"
|
|
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"
|
|
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"
|
|
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"
|
|
# Create mesh
|
|
pie_mesh = bpy.data.meshes.new('Pie')
|
|
|
|
# Create object
|
|
pie = bpy.data.objects.new('Pie', pie_mesh)
|
|
|
|
# Link object to scene
|
|
bpy.context.scene.collection.objects.link(pie)
|
|
# Get a BMesh representation
|
|
bm = bmesh.new() # create an empty BMesh
|
|
bm.from_mesh(pie_mesh) # fill it in from a Mesh
|
|
|
|
# Hot to create vertices
|
|
v_0 = bm.verts.new((0.0, -1.0, 0.0))
|
|
v_1 = bm.verts.new((-1.0, -1.0, 1.0))
|
|
v_2 = bm.verts.new((0.0, 1.0, 0.0))
|
|
v_3 = bm.verts.new((-1.0, 1.0, 1.0))
|
|
v_4 = bm.verts.new((1.0, -1.0, 1.0))
|
|
v_5 = bm.verts.new((1.0, 1.0, 1.0))
|
|
|
|
# Initialize the index values of this sequence.
|
|
bm.verts.index_update()
|
|
|
|
# How to create a face
|
|
# it's not necessary to create the edges before, I made it only to show how create
|
|
# edges too
|
|
bm.faces.new((v_0, v_1, v_3, v_2))
|
|
bm.faces.new((v_0, v_2, v_5, v_4))
|
|
|
|
# Finish up, write the bmesh back to the mesh
|
|
bm.to_mesh(pie_mesh)
|
|
bpy.context.view_layer.objects.active = pie
|
|
|
|
cutter_obj = bpy.context.active_object
|
|
cutter_obj.visible_camera = False
|
|
cutter_obj.visible_diffuse = False
|
|
cutter_obj.visible_glossy = False
|
|
cutter_obj.visible_transmission = False
|
|
cutter_obj.visible_volume_scatter = False
|
|
cutter_obj.visible_shadow = False
|
|
cutter_obj.hide_render = True
|
|
cutter_obj.display_type = 'WIRE'
|
|
|
|
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')
|
|
if len(output_node.inputs[0].links) == 0:
|
|
node_group.links.new(cut_node.outputs[0],
|
|
output_node.inputs[0])
|
|
move_node_to_node(cut_node, output_node, (-300, 0))
|
|
else:
|
|
pre_output_node = output_node.inputs[0].links[0].from_node
|
|
node_group.links.new(pre_output_node.outputs[0],
|
|
cut_node.inputs[0])
|
|
node_group.links.new(cut_node.outputs[0],
|
|
output_node.inputs[0])
|
|
move_node_between_nodes(cut_node,
|
|
[pre_output_node, output_node])
|
|
|
|
node_group.links.new(cutter_node.outputs[0],
|
|
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)
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
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"
|
|
|
|
|
|
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"
|
|
|
|
|
|
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"
|
|
|
|
|
|
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"
|
|
|
|
|
|
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"
|