From cb40391e0d1c45d83ba5edac195b25b3fe561dab Mon Sep 17 00:00:00 2001 From: themancalledjakob Date: Fri, 15 Nov 2024 20:16:59 +0100 Subject: [PATCH 1/4] print to stderr --- common/utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/utils.py b/common/utils.py index d45cd8c..e9757b4 100644 --- a/common/utils.py +++ b/common/utils.py @@ -68,6 +68,10 @@ def open_file_browser(directory): # xdg-open *should* be supported by recent Gnome, KDE, Xfce +def printerr(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + + # # Evaluate a bezier curve for the parameter 0<=t<=1 along its length # def evaluateBezierPoint(p1, h1, h2, p2, t): # return ((1 - t)**3) * p1 + (3 * t * (1 - t)**2) * h1 + (3 * (t**2) * (1 - t)) * h2 + (t**3) * p2 From 0320a18002667cf851101f5a5a71c4ac02cee842 Mon Sep 17 00:00:00 2001 From: themancalledjakob Date: Fri, 15 Nov 2024 20:17:28 +0100 Subject: [PATCH 2/4] bpy_to_abspath --- butils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/butils.py b/butils.py index af7617d..ebef8b0 100644 --- a/butils.py +++ b/butils.py @@ -392,6 +392,9 @@ def move_in_fontcollection(obj, fontcollection, allow_duplicates=False): return obj +def bpy_to_abspath(blender_path): + return os.path.realpath(bpy.path.abspath(blender_path)) + def register_font_from_filepath(filepath): from .bimport import get_font_faces_in_file From b24d0dbca494fe8e656a9df1680c9ffb3d6d3950 Mon Sep 17 00:00:00 2001 From: themancalledjakob Date: Fri, 15 Nov 2024 20:17:50 +0100 Subject: [PATCH 3/4] cross-platform acrobatics --- bimport.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bimport.py b/bimport.py index a1c88b7..2ec6f58 100644 --- a/bimport.py +++ b/bimport.py @@ -424,7 +424,13 @@ class ImportGLTF2(Operator, ConvertGLTF2_Base, ImportHelper): elapsed_s = "{:.2f}s".format(time.time() - start_time) print("font import gltf finished in " + elapsed_s) - gltf.log.removeHandler(gltf.log_handler) + # acrobatics to not break on MacOS + if hasattr(gltf, "log_handler"): + if hasattr(gltf.log, "removeHandler"): + gltf.log.removeHandler(gltf.log_handler) + elif hasattr(gltf.log, "logger"): + if hasattr(gltf.log.logger, "removeHandler"): + gltf.log.logger.removeHandler(gltf.log_handler) return {'FINISHED'} From f6b1649c71be64fa750a5a80d2e942efb06557f6 Mon Sep 17 00:00:00 2001 From: themancalledjakob Date: Fri, 15 Nov 2024 20:24:06 +0100 Subject: [PATCH 4/4] smoother install font & depsgraph update when we set a text, we don't want our manual depsgraph update, because this would trigger another setting of the text, which would trigger the manual depsgraph update, which would trigger another setting of the text, which would trigger the manual depsgraph update, which will eventually be too much. So, we ignore the depsgraph update n-times, where "n = n-letters + 1". worst side effect: might not update the text automatically in edge cases. --- __init__.py | 104 +++++++++++++++++++++++++++------------------------- butils.py | 2 + 2 files changed, 57 insertions(+), 49 deletions(-) diff --git a/__init__.py b/__init__.py index c68b1f7..c8575d2 100644 --- a/__init__.py +++ b/__init__.py @@ -326,31 +326,32 @@ class ABC3D_PT_Panel(bpy.types.Panel): icon = 'ERROR' layout.row().label(text='no fonts loaded yet') + layout.operator(f"{__name__}.install_font", text='Install new font') layout.operator(f"{__name__}.load_installed_fonts", text="load installed fonts", icon=icon) layout.operator(f"{__name__}.open_asset_directory", text="open asset directory", icon='FILEBROWSER') -class ABC3D_PT_LoadFontPanel(bpy.types.Panel): - bl_label = "Install a new font" - bl_parent_id = "ABC3D_PT_Panel" - bl_category = "ABC3D" - bl_space_type = "VIEW_3D" - bl_region_type = "UI" +# class ABC3D_PT_LoadFontPanel(bpy.types.Panel): + # bl_label = "Install a new font" + # bl_parent_id = "ABC3D_PT_Panel" + # bl_category = "ABC3D" + # bl_space_type = "VIEW_3D" + # bl_region_type = "UI" - def draw(self, context): - layout = self.layout - wm = context.window_manager - scene = context.scene + # def draw(self, context): + # layout = self.layout + # wm = context.window_manager + # scene = context.scene - abc3d_data = scene.abc3d_data + # abc3d_data = scene.abc3d_data - box = layout.box() - box.row().label(text="1. Select fontfile") - box.row().prop(context.scene.abc3d_data, "font_path") - box.row().label(text="2. Install it:") - box.row().operator(f"{__name__}.install_font", text='Install new font') + # box = layout.box() + # box.row().label(text="1. Select fontfile") + # box.row().prop(context.scene.abc3d_data, "font_path") + # box.row().label(text="2. Install it:") + # box.row().operator(f"{__name__}.install_font", text='Install new font') class ABC3D_PT_FontList(bpy.types.Panel): @@ -666,7 +667,7 @@ class ABC3D_OT_InstallFont(bpy.types.Operator): description="Install a *.glb or *.gltf fontfile from disk", default="", maxlen=1024, - # update=font_path_update_callback, + update=font_path_update_callback, subtype="FILE_PATH") install_in_assets: bpy.props.BoolProperty( @@ -682,7 +683,7 @@ class ABC3D_OT_InstallFont(bpy.types.Operator): def draw(self, context): abc3d_data = context.scene.abc3d_data layout = self.layout - # layout.row().prop(self, "font_path") # crashes on Mac OS? + layout.row().prop(self, "font_path") # layout.row().prop(abc3d_data, "font_path") # closes the stupid panel on Mac OS.. layout.row().prop(self, "install_in_assets") if not self.install_in_assets and not self.load_into_memory: @@ -698,30 +699,30 @@ class ABC3D_OT_InstallFont(bpy.types.Operator): layout.label(text="load the font data on demand.") def invoke(self, context, event): - abc3d_data = context.scene.abc3d_data - self.font_path = abc3d_data.font_path - if not os.path.exists(self.font_path): - bpy.app.timers.register(lambda: butils.ShowMessageBox( - title=f"{__name__} Warning", - icon="ERROR", - message=[ - f"We believe the font path ({self.font_path}) does not exist.", - f"Did you select your fontfile in the field above the 'Install new font'-button?", - ], - ), first_interval=0.1) + # self.font_path = butils.bpy_to_abspath(self.font_path) + # if not os.path.exists(self.font_path): + # bpy.app.timers.register(lambda: butils.ShowMessageBox( + # title=f"{__name__} Warning", + # icon="ERROR", + # message=[ + # f"We believe the font path ({self.font_path}) does not exist.", + # f"Did you select your fontfile in the field above the 'Install new font'-button?", + # ], + # ), first_interval=0.1) return context.window_manager.invoke_props_dialog(self) def execute(self, context): scene = bpy.context.scene abc3d_data = context.scene.abc3d_data - if not os.path.exists(self.font_path): + font_path = butils.bpy_to_abspath(self.font_path) + if not os.path.exists(font_path): butils.ShowMessageBox( title=f"{__name__} Warning", icon="ERROR", message=[ f"Could not install font.", - f"We believe the font path ({self.font_path}) does not exist.", + f"We believe the font path ({font_path}) does not exist.", f"If this is an error, please let us know.", ], ) @@ -729,11 +730,11 @@ class ABC3D_OT_InstallFont(bpy.types.Operator): if self.install_in_assets: preferences = getPreferences(context) - filename = os.path.basename(self.font_path) + filename = os.path.basename(font_path) target = os.path.join(preferences.assets_dir, "fonts", filename) import shutil os.makedirs(os.path.dirname(target), exist_ok=True) - shutil.copyfile(self.font_path, target) + shutil.copyfile(font_path, target) # def register_load(target, load=False): # print(f"registering installed fonts") # bpy.app.timers.register(lambda: register_load(target, self.load_into_memory), first_interval=5) @@ -742,9 +743,9 @@ class ABC3D_OT_InstallFont(bpy.types.Operator): butils.load_font_from_filepath(target) butils.update_available_fonts() else: - butils.register_font_from_filepath(self.font_path) + butils.register_font_from_filepath(font_path) if self.load_into_memory: - butils.load_font_from_filepath(self.font_path) + butils.load_font_from_filepath(font_path) return {'FINISHED'} @@ -1507,7 +1508,7 @@ classes = ( ABC3D_UL_fonts, ABC3D_UL_texts, ABC3D_PT_Panel, - ABC3D_PT_LoadFontPanel, + # ABC3D_PT_LoadFontPanel, ABC3D_PT_FontList, ABC3D_PT_TextPlacement, ABC3D_PT_TextManagement, @@ -1585,7 +1586,7 @@ def load_used_glyphs(): [f"Font {t.font_name} is there,", f"but the FontFace {t.face_name} is missing,", "Do you have it installed?"]) - if len(a["maybe"]) > 0: + elif len(a["maybe"]) > 0: for fp in a["filepaths"]: butils.load_font_from_filepath(fp, a["maybe"]) @@ -1610,20 +1611,25 @@ def on_frame_changed(self, dummy): # TODO PERFORMANCE: only on demand butils.set_text_on_curve(t) - @persistent def on_depsgraph_update(scene, depsgraph): - for u in depsgraph.updates: - if f"{utils.prefix()}_linked_textobject" in u.id.keys() \ - and f"{utils.prefix()}_type" in u.id.keys() \ - and u.id[f"{utils.prefix()}_type"] == 'textobject': - linked_textobject = u.id[f"{utils.prefix()}_linked_textobject"] - if u.is_updated_geometry and len(scene.abc3d_data.available_texts) > linked_textobject and not "prevent_recursion" in u.id: - u.id["prevent_recursion"] = True - butils.set_text_on_curve( - scene.abc3d_data.available_texts[linked_textobject]) - elif "prevent_recursion" in u.id.keys(): - del u.id["prevent_recursion"] + if not bpy.context.mode.startswith("EDIT"): + for u in depsgraph.updates: + if f"{utils.prefix()}_linked_textobject" in u.id.keys() \ + and f"{utils.prefix()}_type" in u.id.keys() \ + and u.id[f"{utils.prefix()}_type"] == 'textobject': + linked_textobject = u.id[f"{utils.prefix()}_linked_textobject"] + if u.is_updated_geometry and len(scene.abc3d_data.available_texts) > linked_textobject: + def later(): + if not "lock_depsgraph_update_ntimes" in scene.abc3d_data \ + or scene.abc3d_data["lock_depsgraph_update_ntimes"] == 0: + print("******* not yet") + butils.set_text_on_curve( + scene.abc3d_data.available_texts[linked_textobject]) + elif scene.abc3d_data["lock_depsgraph_update_ntimes"] > 0: + scene.abc3d_data['lock_depsgraph_update_ntimes'] -= 1 + butils.run_in_main_thread(later) + def register(): diff --git a/butils.py b/butils.py index ebef8b0..c6737be 100644 --- a/butils.py +++ b/butils.py @@ -860,6 +860,8 @@ def set_text_on_curve(text_properties, recursive=True): mom[f"{utils.prefix()}_translation"] = text_properties.translation bpy.context.view_layer.objects.active = mom bpy.ops.object.parent_set(type='OBJECT') + bpy.context.scene.abc3d_data["lock_depsgraph_update_ntimes"] = len(bpy.context.selected_objects) + mom["lock_depsgraph_update_ntimes"] = len(bpy.context.selected_objects) # endtime = time.perf_counter_ns() # elapsedtime = endtime - starttime