diff --git a/bseq/__init__.py b/bseq/__init__.py index abcd742..edaf58c 100644 --- a/bseq/__init__.py +++ b/bseq/__init__.py @@ -1,36 +1,18 @@ -from .operators import BSEQ_OT_load, BSEQ_OT_edit, BSEQ_OT_resetpt, BSEQ_OT_resetmesh, BSEQ_OT_resetins,BSEQ_OT_set_as_split_norm,BSEQ_OT_remove_split_norm,BSEQ_OT_disable_selected,BSEQ_OT_enable_selected,BSEQ_OT_refresh_seq -from .properties import BSEQ_scene_property, BSEQ_obj_property,BSEQ_mesh_property +from bseq.utils import refresh_obj +from .operators import BSEQ_OT_load, BSEQ_OT_edit, BSEQ_OT_resetpt, BSEQ_OT_resetmesh, BSEQ_OT_resetins, BSEQ_OT_set_as_split_norm, BSEQ_OT_remove_split_norm, BSEQ_OT_disable_selected, BSEQ_OT_enable_selected, BSEQ_OT_refresh_seq +from .properties import BSEQ_scene_property, BSEQ_obj_property, BSEQ_mesh_property from .panels import BSEQ_UL_Obj_List, BSEQ_List_Panel, BSEQ_Settings, BSEQ_Import, BSEQ_Templates, BSEQ_UL_Att_List, draw_template from .messenger import subscribe_to_selected, unsubscribe_to_selected import bpy from bpy.app.handlers import persistent from .importer import update_obj -from datetime import datetime - - -def print_information(scene): - if not bpy.context.scene.BSEQ.print: - return - now = datetime.now() - path = bpy.context.scene.render.filepath - path = bpy.path.abspath(path) - filepath = path + '/bseq_' + now.strftime("%Y-%m-%d_%H-%M") - with open(filepath, 'w') as file: - file.write("Render Time: {}\n".format(now.strftime("%Y-%m-%d_%H-%M"))) - file.write("bseq Objects in the scene:\n\n") - for obj in bpy.data.objects: - bseq_prop = obj.BSEQ - if bseq_prop.init: - file.write("Object name: {}\n".format(obj.name)) - file.write("Is it being animated: {}\n".format(bseq_prop.enabled)) - file.write("Filepath: {}\n".format(bseq_prop.pattern)) - file.write("Is it relative path: {}\n".format(bseq_prop.use_relative)) - file.write("\n\n") +from .globals import * @persistent def BSEQ_initialize(scene): if update_obj not in bpy.app.handlers.frame_change_post: + bpy.app.handlers.frame_change_post.append(auto_refresh) bpy.app.handlers.frame_change_post.append(update_obj) subscribe_to_selected() if print_information not in bpy.app.handlers.render_init: diff --git a/bseq/callback.py b/bseq/callback.py index 02b41a9..a2c6ece 100644 --- a/bseq/callback.py +++ b/bseq/callback.py @@ -48,4 +48,7 @@ def update_selected_obj_num(self, context): def poll_material(self, material): - return not material.is_grease_pencil \ No newline at end of file + return not material.is_grease_pencil + +def poll_edit_obj(self, object): + return object.BSEQ.init \ No newline at end of file diff --git a/bseq/globals.py b/bseq/globals.py new file mode 100644 index 0000000..5577a71 --- /dev/null +++ b/bseq/globals.py @@ -0,0 +1,41 @@ +# here are the implementations of global settings + +import bpy +from datetime import datetime +import os +from .utils import refresh_obj + +def print_information(scene): + if not bpy.context.scene.BSEQ.print: + return + now = datetime.now() + path = bpy.context.scene.render.filepath + path = bpy.path.abspath(path) + if not os.path.isdir(path): + # by default, path is '/tmp', and it does not exist on windows system + return + filepath = path + '/bseq_' + now.strftime("%Y-%m-%d_%H-%M") + with open(filepath, 'w') as file: + file.write("Render Time: {}\n".format(now.strftime("%Y-%m-%d_%H-%M"))) + file.write("bseq Objects in the scene:\n\n") + for obj in bpy.data.objects: + bseq_prop = obj.BSEQ + if bseq_prop.init: + file.write("Object name: {}\n".format(obj.name)) + file.write("Is it being animated: {}\n".format(bseq_prop.enabled)) + file.write("Filepath: {}\n".format(bseq_prop.pattern)) + file.write("Is it relative path: {}\n".format(bseq_prop.use_relative)) + file.write("\n\n") + + +def auto_refresh(scene, depsgraph=None): + if not bpy.context.scene.BSEQ.auto_refresh: + return + for obj in bpy.data.objects: + if obj.BSEQ.init == False: + continue + if obj.BSEQ.enabled == False: + continue + if obj.mode != "OBJECT": + continue + refresh_obj(obj) \ No newline at end of file diff --git a/bseq/importer.py b/bseq/importer.py index 972b14b..4c896d0 100644 --- a/bseq/importer.py +++ b/bseq/importer.py @@ -164,6 +164,8 @@ def create_obj(fileseq, use_relaitve, transform_matrix=Matrix([[1, 0, 0, 0], [0, object.BSEQ.init = True object.BSEQ.enabled = enabled object.matrix_world = transform_matrix + driver = object.driver_add("BSEQ.frame") + driver.driver.expression = 'frame' if enabled: update_mesh(meshio_mesh, object.data) bpy.context.collection.objects.link(object) @@ -172,16 +174,16 @@ def create_obj(fileseq, use_relaitve, transform_matrix=Matrix([[1, 0, 0, 0], [0, def update_obj(scene, depsgraph=None): - # TODO if bpy in edit mode, then return - - current_frame = bpy.context.scene.frame_current for obj in bpy.data.objects: if obj.BSEQ.init == False: continue if obj.BSEQ.enabled == False: continue + if obj.mode != "OBJECT": + continue + current_frame = obj.BSEQ.frame meshio_mesh = None pattern = obj.BSEQ.pattern if obj.BSEQ.use_relative: diff --git a/bseq/messenger.py b/bseq/messenger.py index e497e74..d2956f5 100644 --- a/bseq/messenger.py +++ b/bseq/messenger.py @@ -10,7 +10,8 @@ def selected_callback(): bpy.context.scene.BSEQ.selected_obj_deselectall_flag = False bpy.context.scene.BSEQ.selected_obj_num = idx bpy.context.scene.BSEQ.selected_obj_deselectall_flag = True - + if bpy.context.active_object.BSEQ.init: + bpy.context.scene.BSEQ.edit_obj = bpy.context.active_object def subscribe_to_selected(): import bseq diff --git a/bseq/operators.py b/bseq/operators.py index 78106e4..05592d1 100644 --- a/bseq/operators.py +++ b/bseq/operators.py @@ -2,7 +2,7 @@ import fileseq from .messenger import * import traceback -from .utils import show_message_box +from .utils import refresh_obj, show_message_box from .importer import create_obj import numpy as np @@ -79,10 +79,12 @@ def execute(self, context): return {"CANCELLED"} sim_loader = context.scene.BSEQ + + # logic here # it seems quite simple task, no need to create a function(for now) - if sim_loader.selected_obj_num >= len(bpy.data.objects): + obj = sim_loader.edit_obj + if not obj: return {"CANCELLED"} - obj = bpy.data.objects[sim_loader.selected_obj_num] if importer_prop.relative: obj.BSEQ.pattern = bpy.path.relpath(str(fs)) else: @@ -110,7 +112,7 @@ def execute(self, context): gn = obj.modifiers.new("BSEQ_GeometryNodse", "NODES") # change starting from blender 3.2 # https://developer.blender.org/rB08b4b657b64f - if bpy.app.version >= (3,2,0): + if bpy.app.version >= (3, 2, 0): bpy.ops.node.new_geometry_node_group_assign() gn.node_group.nodes.new('GeometryNodeMeshToPoints') set_material = gn.node_group.nodes.new('GeometryNodeSetMaterial') @@ -145,7 +147,7 @@ def execute(self, context): gn = obj.modifiers.new("BSEQ_GeometryNodse", "NODES") # change starting from blender 3.2 # https://developer.blender.org/rB08b4b657b64f - if bpy.app.version >= (3,2,0): + if bpy.app.version >= (3, 2, 0): bpy.ops.node.new_geometry_node_group_assign() bpy.ops.object.modifier_move_to_index(modifier=gn.name, index=0) return {"FINISHED"} @@ -170,7 +172,7 @@ def execute(self, context): gn = obj.modifiers.new("BSEQ_GeometryNodse", "NODES") # change starting from blender 3.2 # https://developer.blender.org/rB08b4b657b64f - if bpy.app.version >= (3,2,0): + if bpy.app.version >= (3, 2, 0): bpy.ops.node.new_geometry_node_group_assign() nodes = gn.node_group.nodes links = gn.node_group.links @@ -268,15 +270,6 @@ class BSEQ_OT_refresh_seq(bpy.types.Operator): def execute(self, context): scene = context.scene obj = bpy.data.objects[scene.BSEQ.selected_obj_num] - - fs = obj.BSEQ.pattern - if obj.BSEQ.use_relative: - fs = bpy.path.abspath(fs) - fs = fileseq.findSequenceOnDisk(fs) - fs = fileseq.findSequenceOnDisk(fs.dirname() + fs.basename() + "@" + fs.extension()) - fs = str(fs) - if obj.BSEQ.use_relative: - fs = bpy.path.relpath(fs) - obj.BSEQ.pattern = fs + refresh_obj(obj) return {"FINISHED"} diff --git a/bseq/panels.py b/bseq/panels.py index b009476..7467fe7 100644 --- a/bseq/panels.py +++ b/bseq/panels.py @@ -26,8 +26,10 @@ def draw_item(self, context, layout, data, item, icon, active_data, active_propn row.prop(item, "name", text='Name ', emboss=False) if item.BSEQ.enabled: row.prop(item.BSEQ, "enabled", text = "ENABLED", icon="PLAY") + row.prop(item.BSEQ, "frame", text = "Current Frame:") else: row.prop(item.BSEQ, "enabled", text = "DISABLED", icon="PAUSE") + row.label(text = "Animation Stopped") else: # actually, I guess this line of code won't be executed? layout.label(text="", translate=False, icon_value=icon) @@ -71,8 +73,6 @@ def draw(self, context): row = layout.row() row.operator("bseq.enableselected", text="Enable Selected") row.operator("bseq.disableselected", text="Disable Selected") - row = layout.row() - row.operator("sequence.edit", text="Edit Path") row.operator("bseq.refresh", text="Refresh") @@ -193,6 +193,11 @@ def draw(self, context): col2.prop(importer_prop, "relative", text="") layout.operator("sequence.load") + split = layout.split() + col1 = split.column() + col2 = split.column() + col1.prop_search(importer_prop, 'edit_obj', bpy.data, 'objects', text="") + col2.operator("sequence.edit") layout.label(text="Global Settings") box = layout.box() @@ -203,6 +208,8 @@ def draw(self, context): col1.label(text="Print Sequence Information on Render") col2.prop(importer_prop, "print", text="") + col1.label(text="Auto refresh all the sequence every frame") + col2.prop(importer_prop, "auto_refresh", text="") class BSEQ_Templates(bpy.types.Menu): diff --git a/bseq/properties.py b/bseq/properties.py index 5cfcb9f..73e1ded 100644 --- a/bseq/properties.py +++ b/bseq/properties.py @@ -32,10 +32,19 @@ class BSEQ_scene_property(bpy.types.PropertyGroup): poll=poll_material, ) + edit_obj: bpy.props.PointerProperty( + type=bpy.types.Object, + poll=poll_edit_obj, + ) + print: bpy.props.BoolProperty(name='print', description="whether or not to print additional information when rendering", default=True) + auto_refresh: bpy.props.BoolProperty(name='auto refresh', + description="whether or not to auto refresh all the sequence every frame", + default=False) + class BSEQ_obj_property(bpy.types.PropertyGroup): init: bpy.props.BoolProperty(default=False) @@ -45,6 +54,7 @@ class BSEQ_obj_property(bpy.types.PropertyGroup): script_name: bpy.props.StringProperty() use_relative: bpy.props.BoolProperty(default=False) pattern: bpy.props.StringProperty() + frame: bpy.props.IntProperty() # set this property for mesh, not object (maybe change later?) diff --git a/bseq/utils.py b/bseq/utils.py index 7896675..775ee6b 100644 --- a/bseq/utils.py +++ b/bseq/utils.py @@ -1,5 +1,5 @@ import bpy - +import fileseq def show_message_box(message="", title="Message Box", icon="INFO"): ''' @@ -24,3 +24,15 @@ def stop_animation(): # if playing animation, then stop it, otherwise it will keep showing message box bpy.ops.screen.animation_cancel() + + +def refresh_obj(obj): + fs = obj.BSEQ.pattern + if obj.BSEQ.use_relative: + fs = bpy.path.abspath(fs) + fs = fileseq.findSequenceOnDisk(fs) + fs = fileseq.findSequenceOnDisk(fs.dirname() + fs.basename() + "@" + fs.extension()) + fs = str(fs) + if obj.BSEQ.use_relative: + fs = bpy.path.relpath(fs) + obj.BSEQ.pattern = fs \ No newline at end of file