228 lines
8.5 KiB
Python
228 lines
8.5 KiB
Python
import bpy
|
|
from pathlib import Path
|
|
import shutil
|
|
from .utils import get_cache_dir
|
|
from ..nodes import custom_nodes
|
|
from ..bioxelutils.utils import (get_container_objs_from_selection,
|
|
get_all_layer_objs,
|
|
get_container_layer_objs)
|
|
|
|
CLASS_PREFIX = "BIOXELNODES_MT_NODES"
|
|
|
|
|
|
class ReLinkNodes(bpy.types.Operator):
|
|
bl_idname = "bioxelnodes.relink_nodes"
|
|
bl_label = "Relink Nodes to Addon"
|
|
bl_description = "Relink all nodes to addon source"
|
|
|
|
def execute(self, context):
|
|
file_name = Path(custom_nodes.nodes_file).name
|
|
for lib in bpy.data.libraries:
|
|
lib_path = Path(bpy.path.abspath(lib.filepath)).resolve()
|
|
lib_name = lib_path.name
|
|
if lib_name == file_name:
|
|
if str(lib_path) != custom_nodes.nodes_file:
|
|
lib.filepath = custom_nodes.nodes_file
|
|
|
|
self.report({"INFO"}, f"Successfully relinked.")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class SaveStagedData(bpy.types.Operator):
|
|
bl_idname = "bioxelnodes.save_staged_data"
|
|
bl_label = "Save Staged Data"
|
|
bl_description = "Save all staged data in this file for sharing"
|
|
|
|
save_cache: bpy.props.BoolProperty(
|
|
name="Save Layer Caches",
|
|
default=True,
|
|
) # type: ignore
|
|
|
|
cache_dir: bpy.props.StringProperty(
|
|
name="Cache Directory",
|
|
subtype='DIR_PATH',
|
|
default="//"
|
|
) # type: ignore
|
|
|
|
save_lib: bpy.props.BoolProperty(
|
|
name="Save Node Library File",
|
|
default=True,
|
|
) # type: ignore
|
|
|
|
lib_dir: bpy.props.StringProperty(
|
|
name="Library Directory",
|
|
subtype='DIR_PATH',
|
|
default="//"
|
|
) # type: ignore
|
|
|
|
def execute(self, context):
|
|
if self.save_lib:
|
|
files = []
|
|
for classname in dir(bpy.types):
|
|
if CLASS_PREFIX in classname:
|
|
cls = getattr(bpy.types, classname)
|
|
files.append(cls.nodes_file)
|
|
files = list(set(files))
|
|
|
|
for file in files:
|
|
file_name = Path(file).name
|
|
# "//"
|
|
lib_dir = bpy.path.abspath(self.lib_dir)
|
|
|
|
output_path: Path = Path(lib_dir, file_name).resolve()
|
|
source_path: Path = Path(file).resolve()
|
|
|
|
if output_path != source_path:
|
|
shutil.copy(source_path, output_path)
|
|
|
|
for lib in bpy.data.libraries:
|
|
lib_path = Path(bpy.path.abspath(lib.filepath)).resolve()
|
|
if lib_path == source_path:
|
|
blend_path = Path(bpy.path.abspath("//")).resolve()
|
|
lib.filepath = bpy.path.relpath(
|
|
str(output_path), start=str(blend_path))
|
|
|
|
self.report({"INFO"}, f"Successfully saved to {output_path}")
|
|
|
|
if self.save_cache:
|
|
fails = []
|
|
for layer_obj in get_all_layer_objs():
|
|
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_obj.name for layer_obj in fails])} fail to save.")
|
|
|
|
return {'FINISHED'}
|
|
|
|
def invoke(self, context, event):
|
|
context.window_manager.invoke_props_dialog(self,
|
|
width=500)
|
|
return {'RUNNING_MODAL'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return bpy.data.is_saved
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
panel = layout.box()
|
|
panel.prop(self, "save_cache")
|
|
panel.prop(self, "cache_dir")
|
|
panel = layout.box()
|
|
panel.prop(self, "save_lib")
|
|
panel.prop(self, "lib_dir")
|
|
|
|
|
|
class CleanAllCaches(bpy.types.Operator):
|
|
bl_idname = "bioxelnodes.clear_all_caches"
|
|
bl_label = "Clean All Caches in Temp"
|
|
bl_description = "Clean all caches saved in temp"
|
|
|
|
def execute(self, context):
|
|
cache_dir = get_cache_dir(context)
|
|
try:
|
|
shutil.rmtree(cache_dir)
|
|
self.report({"INFO"}, f"Successfully cleaned caches.")
|
|
return {'FINISHED'}
|
|
except:
|
|
self.report({"WARNING"},
|
|
"Fail to clean caches, you may do it manually.")
|
|
return {'CANCELLED'}
|
|
|
|
def invoke(self, context, event):
|
|
context.window_manager.invoke_confirm(self,
|
|
event,
|
|
message="All caches will be cleaned, include other project files, do you still want to clean?")
|
|
return {'RUNNING_MODAL'}
|
|
|
|
|
|
class RenderSettingPreset(bpy.types.Operator):
|
|
bl_idname = "bioxelnodes.render_setting_preset"
|
|
bl_label = "Render Setting Preset"
|
|
bl_description = "Render Setting Preset"
|
|
|
|
PRESETS = {
|
|
"preview_e": "Preview (EEVEE)",
|
|
"preview_c": "Preview (Cycles)",
|
|
"production_e": "Production (EEVEE)",
|
|
"production_c": "Production (Cycles)"
|
|
}
|
|
|
|
preset: bpy.props.EnumProperty(name="Preset",
|
|
default="preview_c",
|
|
items=[(k, v, "")
|
|
for k, v in PRESETS.items()]) # type: ignore
|
|
|
|
def execute(self, context):
|
|
if self.preset == "preview_e":
|
|
bpy.context.scene.render.engine = 'BLENDER_EEVEE_NEXT'
|
|
bpy.context.scene.eevee.use_taa_reprojection = False
|
|
bpy.context.scene.eevee.taa_samples = 16
|
|
bpy.context.scene.eevee.volumetric_tile_size = '2'
|
|
bpy.context.scene.eevee.volumetric_shadow_samples = 128
|
|
bpy.context.scene.eevee.volumetric_samples = 128
|
|
bpy.context.scene.eevee.volumetric_ray_depth = 16
|
|
bpy.context.scene.eevee.use_volumetric_shadows = True
|
|
|
|
elif self.preset == "production_e":
|
|
bpy.context.scene.render.engine = 'BLENDER_EEVEE_NEXT'
|
|
bpy.context.scene.eevee.use_taa_reprojection = False
|
|
bpy.context.scene.eevee.taa_samples = 16
|
|
bpy.context.scene.eevee.volumetric_tile_size = '1'
|
|
bpy.context.scene.eevee.volumetric_shadow_samples = 128
|
|
bpy.context.scene.eevee.volumetric_samples = 256
|
|
bpy.context.scene.eevee.volumetric_ray_depth = 16
|
|
bpy.context.scene.eevee.use_volumetric_shadows = True
|
|
|
|
elif self.preset == "preview_c":
|
|
bpy.context.scene.render.engine = 'CYCLES'
|
|
bpy.context.scene.cycles.shading_system = True
|
|
bpy.context.scene.cycles.volume_bounces = 12
|
|
bpy.context.scene.cycles.transparent_max_bounces = 16
|
|
bpy.context.scene.cycles.volume_preview_step_rate = 1
|
|
bpy.context.scene.cycles.volume_step_rate = 1
|
|
|
|
elif self.preset == "production_c":
|
|
bpy.context.scene.render.engine = 'CYCLES'
|
|
bpy.context.scene.cycles.shading_system = True
|
|
bpy.context.scene.cycles.volume_bounces = 16
|
|
bpy.context.scene.cycles.transparent_max_bounces = 32
|
|
bpy.context.scene.cycles.volume_preview_step_rate = 0.1
|
|
bpy.context.scene.cycles.volume_step_rate = 0.1
|
|
|
|
return {'FINISHED'}
|
|
|
|
class SliceViewer(bpy.types.Operator):
|
|
bl_idname = "bioxelnodes.slice_viewer"
|
|
bl_label = "Slice Viewer"
|
|
bl_description = "Slice Viewer"
|
|
bl_icon = "FILE_VOLUME"
|
|
|
|
def execute(self, context):
|
|
bpy.context.scene.eevee.use_taa_reprojection = False
|
|
bpy.context.scene.eevee.taa_samples = 4
|
|
bpy.context.scene.eevee.volumetric_tile_size = '2'
|
|
bpy.context.scene.eevee.volumetric_shadow_samples = 128
|
|
bpy.context.scene.eevee.volumetric_samples = 128
|
|
bpy.context.scene.eevee.volumetric_ray_depth = 1
|
|
bpy.context.scene.eevee.use_volumetric_shadows = False
|
|
|
|
for area in bpy.context.screen.areas:
|
|
if area.type == 'VIEW_3D':
|
|
area.spaces[0].shading.type = 'MATERIAL'
|
|
area.spaces[0].shading.studio_light = 'studio.exr'
|
|
area.spaces[0].shading.studiolight_intensity = 2.5
|
|
area.spaces[0].shading.use_scene_lights = False
|
|
area.spaces[0].shading.use_scene_world = False
|
|
|
|
|
|
return {'FINISHED'} |