diff --git a/__init__.py b/__init__.py index 9b5d6b7..6857c1c 100644 --- a/__init__.py +++ b/__init__.py @@ -9,7 +9,7 @@ bl_info = { "author": "Jakob Schlötter, Studio Pointer*", "version": (0, 0, 1), "blender": (4, 1, 0), - "location": "wherever it may be", + "location": "VIEW3D", "description": "Does Font3D stuff", "category": "Typography", } @@ -93,7 +93,7 @@ class FONT3D_addonPreferences(bpy.types.AddonPreferences): class FONT3D_OT_Font3D(bpy.types.Operator): """Font 3D""" - bl_idname = "font3d.font3d" + bl_idname = f"{__name__}.font3d" bl_label = "Font 3D" bl_options = {'REGISTER', 'UNDO'} @@ -112,7 +112,7 @@ class FONT3D_OT_Font3D(bpy.types.Operator): class FONT3D_settings(bpy.types.PropertyGroup): font_path: bpy.props.StringProperty( name="Font path", - description="Where is the font", + description="Load a *.glb or *.gltf fontfile from disk", default="", maxlen=1024, subtype="FILE_PATH") @@ -122,14 +122,14 @@ class FONT3D_settings(bpy.types.PropertyGroup): default="_NM_", maxlen=1024, ) - test_text: bpy.props.StringProperty( - name="Test Text", - description="the text to test with", + text: bpy.props.StringProperty( + name="Text", + description="The text.", default="HELLO", maxlen=1024, ) - the_mother_of_typography: bpy.props.PointerProperty( - name="The Mother Of Typography", + target_object: bpy.props.PointerProperty( + name="The Target Object", description="The target, which will be populated by character children of text.", type=bpy.types.Object, ) @@ -137,7 +137,11 @@ class FONT3D_settings(bpy.types.PropertyGroup): name="Letter Spacing", description="Letter Spacing", default=0.0, - options={'ANIMATABLE'}, + ) + orientation: bpy.props.FloatVectorProperty( + name="Orientation", + default=(1.5707963267948966, 0.0, 0.0), # 90 degrees in radians + subtype='EULER', ) class FONT3D_available_font(bpy.types.PropertyGroup): @@ -154,20 +158,6 @@ class FONT3D_glyph_properties(bpy.types.PropertyGroup): class FONT3D_text_properties(bpy.types.PropertyGroup): def update_callback(self, context): butils.set_text_on_curve(self) - # TODO: update when animate - # does not work like this, somehow it does not run in main thread when the text is actually being set - # def get_float(self): - # return self["letter_spacingor"] - # def set_float(self, value): - # print(f"{utils.get_timestamp()} setting float to {value}") - # self["letter_spacingor"] = value - # def fun(text_properties : FONT3D_text_properties): - # # print(text_properties) - # # print(type(text_properties)) - # # print(text_properties.letter_spacing) - # print(f"is running ---------------------------------->>>>>>> {text_properties.letter_spacing} and {text_properties.get('letter_spacingor')}") - # # butils.set_text_on_curve(text_properties) - # butils.run_in_main_thread(lambda: fun(self)) text_id: bpy.props.IntProperty() font_name: bpy.props.StringProperty() font_face: bpy.props.StringProperty() @@ -176,13 +166,18 @@ class FONT3D_text_properties(bpy.types.PropertyGroup): update=update_callback ) letter_spacing: bpy.props.FloatProperty( - # get=get_float, - # set=set_float, update=update_callback, name="Letter Spacing", description="Letter Spacing", + options={'ANIMATABLE'}, step=0.01, ) + orientation: bpy.props.FloatVectorProperty( + update=update_callback, + name="Orientation", + default=(1.5707963267948966, 0.0, 0.0), # 90 degrees in radians + subtype='EULER', + ) distribution_type: bpy.props.StringProperty() glyphs: bpy.props.CollectionProperty(type=FONT3D_glyph_properties) @@ -191,14 +186,25 @@ class FONT3D_data(bpy.types.PropertyGroup): available_fonts: bpy.props.CollectionProperty(type=FONT3D_available_font, name="name of the collection property") active_font_index: bpy.props.IntProperty() available_texts: bpy.props.CollectionProperty(type=FONT3D_text_properties, name="") - active_text_index: bpy.props.IntProperty() + def active_text_index_update(self, context): + if self.active_text_index != -1: + o = self.available_texts[self.active_text_index].text_object + # active_text_index changed. so let's update the selection + # check if it is already selected + # or perhaps one of the glyphs + if not o.select_get() and not len([ c for c in o.children if c.select_get() ]) > 0: + bpy.ops.object.select_all(action="DESELECT") + o.select_set(True) + bpy.context.view_layer.objects.active = o + # else: + # print("already selected") + + active_text_index: bpy.props.IntProperty(update=active_text_index_update) class FONT3D_UL_fonts(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): split = layout.split(factor=0.3) split.label(text="Index: %d" % (index)) - # custom_icon = "OUTLINER_OB_%s" % item.obj_type - # split.prop(item, "name", text="", emboss=False, translate=False) split.label(text=f"{item.font_name}") # avoids renaming the item by accident def invoke(self, context, event): @@ -208,28 +214,101 @@ class FONT3D_UL_texts(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): split = layout.split(factor=0.3) split.label(text="Id: %d" % (item.text_id)) - # custom_icon = "OUTLINER_OB_%s" % item.obj_type - # split.prop(item, "name", text="", emboss=False, translate=False) split.label(text=f"{item.text}") # avoids renaming the item by accident def invoke(self, context, event): pass - -class FONT3D_PT_panel(bpy.types.Panel): - bl_label = "Panel for Font3D" +class FONT3D_PT_Panel(bpy.types.Panel): + bl_label = f"{__name__} panel" bl_category = "Font3D" bl_space_type = "VIEW_3D" bl_region_type = "UI" + def draw(self, context): + layout = self.layout + + layout.label(text=f"{__name__} panel") + + +class FONT3D_PT_LoadFontPanel(bpy.types.Panel): + bl_label = "Load a new font" + bl_parent_id = "FONT3D_PT_Panel" + bl_category = "Font3D" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_options = {"DEFAULT_CLOSED"} + + def draw(self, context): + layout = self.layout + wm = context.window_manager + scene = context.scene + + font3d = scene.font3d + font3d_data = scene.font3d_data + + layout.label(text="Load FontFile:") + layout.row().prop(font3d, "font_path") + layout.row().operator('font3d.loadfont', text='Load Font') + + +class FONT3D_PT_FontList(bpy.types.Panel): + bl_label = "Font List" + bl_parent_id = "FONT3D_PT_Panel" + bl_category = "Font3D" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + + def draw(self, context): + layout = self.layout + wm = context.window_manager + scene = context.scene + + font3d = scene.font3d + font3d_data = scene.font3d_data + + layout.label(text="Loaded Fonts") + layout.template_list("FONT3D_UL_fonts", "", font3d_data, "available_fonts", font3d_data, "active_font_index") + +class FONT3D_PT_TextPlacement(bpy.types.Panel): + bl_label = "Place Text" + bl_parent_id = "FONT3D_PT_Panel" + bl_category = "Font3D" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + + def draw(self, context): + layout = self.layout + wm = context.window_manager + scene = context.scene + + font3d = scene.font3d + font3d_data = scene.font3d_data + + layout.label(text="Set Properties Objects") + layout.row().prop(font3d, "text") + layout.row().prop(font3d, "letter_spacing") + layout.column().prop(font3d, "orientation") + layout.row().operator('font3d.placetext', text='Place Text') + +class FONT3D_PT_TextManagement(bpy.types.Panel): + bl_label = "Text Management" + bl_parent_id = "FONT3D_PT_Panel" + bl_category = "Font3D" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + + # TODO: perhaps this should be done in a periodic timer @classmethod def poll(self, context): scene = context.scene font3d = scene.font3d font3d_data = scene.font3d_data - # TODO: properly include this + # TODO: update available_texts def update(): - font3d_data.active_text_index = -1 + if bpy.context.screen.is_animation_playing: + return + active_text_index = -1 remove_list = [] for i, t in enumerate(font3d_data.available_texts): if type(t.text_object) == type(None): @@ -245,15 +324,15 @@ class FONT3D_PT_panel(bpy.types.Panel): # or they might be lost if type(next((g for g in t.glyphs if type(g.glyph_object) == type(None)), None)) == type(None): g = next((g for g in t.glyphs if type(g.glyph_object) == type(None)), None) - for g in t.glyphs: - if type(g) == type(None): - print("IS NONE") - if type(g.glyph_object) == type(None): - print("go IS NONE") - else: - if g.glyph_object == c: - # print(g.glyph_object.name) - pass + # for g in t.glyphs: + # if type(g) == type(None): + # print("IS NONE") + # if type(g.glyph_object) == type(None): + # print("go IS NONE") + # else: + # if g.glyph_object == c: + # # print(g.glyph_object.name) + # pass if remove_me: remove_list.append(i) @@ -263,10 +342,13 @@ class FONT3D_PT_panel(bpy.types.Panel): for i, t in enumerate(font3d_data.available_texts): if context.active_object == t.text_object: - font3d_data.active_text_index = i + active_text_index = i if (hasattr(context.active_object, "parent") and context.active_object.parent == t.text_object): - font3d_data.active_text_index = i + active_text_index = i + + if active_text_index != font3d_data.active_text_index: + font3d_data.active_text_index = active_text_index butils.run_in_main_thread(update) @@ -280,23 +362,28 @@ class FONT3D_PT_panel(bpy.types.Panel): font3d = scene.font3d font3d_data = scene.font3d_data - layout.label(text="Load FontFile:") - layout.row().prop(font3d, "font_path") - layout.row().operator('font3d.loadfont', text='Load Font') - layout.label(text="Available Fonts") - layout.template_list("FONT3D_UL_fonts", "", font3d_data, "available_fonts", font3d_data, "active_font_index") - layout.label(text='DEBUG') - layout.row().prop(font3d, "test_text") - layout.row().prop(font3d, "the_mother_of_typography") - layout.row().operator('font3d.testfont', text='Distribute') layout.label(text="Text Objects") layout.template_list("FONT3D_UL_texts", "", font3d_data, "available_texts", font3d_data, "active_text_index") - layout.label(text="font properties") - layout.row().prop(font3d, "letter_spacing") + +class FONT3D_PT_FontCreation(bpy.types.Panel): + bl_label = "Font Creation" + bl_parent_id = "FONT3D_PT_Panel" + bl_category = "Font3D" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_options = {"DEFAULT_CLOSED"} + + def draw(self, context): + layout = self.layout + wm = context.window_manager + scene = context.scene + + font3d = scene.font3d + font3d_data = scene.font3d_data + layout.label(text="font creation") layout.row().prop(font3d, "import_infix") layout.row().operator('font3d.create_font_from_objects', text='Create Font') - layout.row().separator() layout.row().operator('font3d.save_font_to_file', text='Save Font To File') layout.row().operator('font3d.toggle_font3d_collection', text='Toggle Collection') layout.row().operator('font3d.temporaryhelper', text='Temporary Helper') @@ -304,7 +391,7 @@ class FONT3D_PT_panel(bpy.types.Panel): class FONT3D_PT_TextPropertiesPanel(bpy.types.Panel): bl_label = "Text Properties" - bl_parent_id = "FONT3D_PT_panel" + bl_parent_id = "FONT3D_PT_TextManagement" bl_category = "Font3D" bl_space_type = "VIEW_3D" bl_region_type = "UI" @@ -333,16 +420,19 @@ class FONT3D_PT_TextPropertiesPanel(bpy.types.Panel): if type(props) == type(None) or type(props.text_object) == type(None): # this should not happen - print("debug: this should not happen") - layout.label(text="AAAAH") + # as then polling does not work + # however, we are paranoid return layout.label(text=f"Mom: {props.text_object.name}") + layout.row().prop(props, "text") layout.row().prop(props, "letter_spacing") + layout.column().prop(props, "orientation") class FONT3D_OT_LoadFont(bpy.types.Operator): - """Load Font 3D""" - bl_idname = "font3d.loadfont" + """Load Fontfile from path above. +(Format must be *.glb or *.gltf)""" + bl_idname = f"{__name__}.loadfont" bl_label = "Load Font" bl_options = {'REGISTER', 'UNDO'} @@ -356,52 +446,21 @@ class FONT3D_OT_LoadFont(bpy.types.Operator): ) return {'CANCELLED'} - # print(f"loading da font at path {scene.font3d.font_path}") if not os.path.exists(scene.font3d.font_path): butils.ShowMessageBox( title=f"{__name__} Warning", icon="ERROR", - message=f"We believe the font path ({scene.font3d.font_path}) does not exist.", + message=f"We believe the font path ({scene[__name__].font_path}) does not exist.", ) return {'CANCELLED'} - currentObjects = [] - for ob in bpy.data.objects: - currentObjects.append(ob.name) - bpy.ops.import_scene.gltf(filepath=scene.font3d.font_path) - - newObjects = [] - - fontcollection = bpy.data.collections.new("Font3D") - scene.collection.children.link(fontcollection) - - font = { - "name": "", - "glyphs": [] - } - - for o in bpy.data.objects: - if o.name not in currentObjects: - if (o.parent == None): - font['name'] = o.name - elif o.parent.name.startswith("glyphs"): - font['glyphs'].append(o) - newObjects.append(o.name) - scene.collection.objects.unlink(o) - fontcollection.objects.link(o) - - try: - shared.fonts - except: - shared.fonts = {} - shared.fonts[font['name']] = Font.Font() - shared.fonts[font['name']]['faces']['regular'] = font + butils.load_font_from_filepath(scene.font3d.font_path) return {'FINISHED'} class FONT3D_OT_TemporaryHelper(bpy.types.Operator): """Temp Font 3D""" - bl_idname = "font3d.temporaryhelper" + bl_idname = f"{__name__}.temporaryhelper" bl_label = "Temp Font" bl_options = {'REGISTER', 'UNDO'} @@ -414,10 +473,10 @@ class FONT3D_OT_TemporaryHelper(bpy.types.Operator): return {'FINISHED'} -class FONT3D_OT_TestFont(bpy.types.Operator): - """Test Font 3D""" - bl_idname = "font3d.testfont" - bl_label = "Test Font" +class FONT3D_OT_PlaceText(bpy.types.Operator): + """Place Text 3D""" + bl_idname = f"{__name__}.placetext" + bl_label = "Place Text" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): @@ -429,8 +488,8 @@ class FONT3D_OT_TestFont(bpy.types.Operator): font3d = scene.font3d font3d_data = scene.font3d_data - if font3d.the_mother_of_typography: - selected = font3d.the_mother_of_typography + if font3d.target_object: + selected = font3d.target_object if selected: font_name = "NM_Origin" @@ -448,8 +507,9 @@ class FONT3D_OT_TestFont(bpy.types.Operator): t.font_name = font_name t.font_face = font_face t.text_object = selected - t.text = scene.font3d.test_text - t.letter_spacing = 0.0 + t.text = scene.font3d.text + t.letter_spacing = scene.font3d.letter_spacing + t.orientation = scene.font3d.orientation t.distribution_type = distribution_type else: butils.ShowMessageBox( @@ -457,14 +517,14 @@ class FONT3D_OT_TestFont(bpy.types.Operator): message=( "Please select an object.", "It will be used to put the type on.", - "You little piece of shit :)"), + "Thank you :)"), icon='GHOST_ENABLED') return {'FINISHED'} class FONT3D_OT_ToggleFont3DCollection(bpy.types.Operator): """Toggle Font3D Collection""" - bl_idname = "font3d.toggle_font3d_collection" + bl_idname = f"{__name__}.toggle_font3d_collection" bl_label = "Toggle Collection visibility" bl_options = {'REGISTER', 'UNDO'} @@ -490,8 +550,6 @@ class FONT3D_OT_SaveFontToFile(bpy.types.Operator): bl_label = "Save Font" bl_options = {'REGISTER', 'UNDO'} - file_path = "whoopwhoop" - def execute(self, context): global shared scene = bpy.context.scene @@ -577,7 +635,7 @@ class FONT3D_OT_SaveFontToFile(bpy.types.Operator): class FONT3D_OT_CreateFontFromObjects(bpy.types.Operator): """Create Font from open objects""" - bl_idname = "font3d.create_font_from_objects" + bl_idname = f"{__name__}.create_font_from_objects" bl_label = "Create Font" bl_options = {'REGISTER', 'UNDO'} @@ -646,7 +704,7 @@ class FONT3D_OT_CreateFontFromObjects(bpy.types.Operator): class FONT3D_PT_RightPropertiesPanel(bpy.types.Panel): """Creates a Panel in the Object properties window""" - bl_label = f"{__name__}" + bl_label = f"{bl_info['name']}" bl_idname = "FONT3D_PT_RightPropertiesPanel" bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' @@ -684,11 +742,9 @@ class FONT3D_PT_RightPropertiesPanel(bpy.types.Panel): row.label(text="text object is: " + textobject.name) row = layout.row() row.label(text=f"active text index is: {font3d_data.active_text_index}") - row = layout.row() - row.prop(available_text, "text") - row = layout.row() - row.prop(available_text, "letter_spacing") - + layout.row().prop(available_text, "text") + layout.row().prop(available_text, "letter_spacing") + layout.column().prop(available_text, "orientation") classes = ( @@ -701,10 +757,15 @@ classes = ( FONT3D_settings, FONT3D_UL_fonts, FONT3D_UL_texts, - FONT3D_PT_panel, + FONT3D_PT_Panel, + FONT3D_PT_LoadFontPanel, + FONT3D_PT_FontList, + FONT3D_PT_TextPlacement, + FONT3D_PT_TextManagement, + FONT3D_PT_FontCreation, FONT3D_PT_TextPropertiesPanel, FONT3D_OT_TemporaryHelper, - FONT3D_OT_TestFont, + FONT3D_OT_PlaceText, FONT3D_OT_LoadFont, FONT3D_OT_ToggleFont3DCollection, FONT3D_OT_SaveFontToFile, @@ -721,6 +782,16 @@ def load_handler_unload(): if bpy.app.timers.is_registered(butils.execute_queued_functions): bpy.app.timers.unregister(butils.execute_queued_functions) +@persistent +def on_frame_changed(self, dummy): + for t in bpy.context.scene.font3d_data.available_texts: + # TODO PERFORMANCE: only on demand + butils.set_text_on_curve(t) + # for i, t in enumerate(bpy.context.scene.font3d_data.available_texts): + # # TODO PERFORMANCE: only on demand + # # butils.set_text_on_curve(t) + # pass + def register(): for cls in classes: bpy.utils.register_class(cls) @@ -735,68 +806,11 @@ def register(): # and autostart if we reload script load_handler(None, None) - # clear available fonts - def clear_available_fonts(): - bpy.context.scene.font3d_data.available_fonts.clear() + if on_frame_changed not in bpy.app.handlers.frame_change_post: + bpy.app.handlers.frame_change_post.append(on_frame_changed) - def load_available_fonts(): - global shared - preferences = getPreferences(bpy.context) - - currentObjects = [] - for ob in bpy.data.objects: - currentObjects.append(ob.name) - - print(f"assets folder: {preferences.assets_dir}") - font_dir = f"{preferences.assets_dir}/fonts" - for file in os.listdir(font_dir): - if file.endswith(".glb"): - font_path = os.path.join(font_dir, file) - bpy.ops.import_scene.gltf(filepath=font_path) - - fontcollection = bpy.data.collections.get("Font3D") - if fontcollection is None: - fontcollection = bpy.data.collections.new("Font3D") - - remove_list = [] - all_objects = [] - for o in bpy.data.objects: - all_objects.append(o) - for o in all_objects: - if o.name not in currentObjects: - # must be new - if ("glyph" in o.keys() - and "face_name" in o.keys() - and "font_name" in o.keys()): - glyph_id = o["glyph"] - font_name = o["font_name"] - face_name = o["face_name"] - butils.move_in_fontcollection( - o, - fontcollection) - Font.add_glyph( - font_name, - face_name, - glyph_id, - o) - - font3d_data = bpy.context.scene.font3d_data - found = False - for f in font3d_data.available_fonts.values(): - if f.font_name == font_name: - found = True - break - if not found: - f = font3d_data.available_fonts.add() - f.font_name = font_name - print(f"font3d added {font_name}") - else: - remove_list.append(o) - for o in remove_list: - bpy.data.objects.remove(o, do_unlink=True) - - butils.run_in_main_thread(clear_available_fonts) - butils.run_in_main_thread(load_available_fonts) + butils.run_in_main_thread(butils.clear_available_fonts) + butils.run_in_main_thread(butils.load_available_fonts) def unregister(): for cls in classes: @@ -808,6 +822,9 @@ def unregister(): # and when reload script load_handler_unload() + if on_frame_changed in bpy.app.handlers.frame_change_post: + bpy.app.handlers.frame_change_post.remove(on_frame_changed) + del bpy.types.Scene.font3d del bpy.types.Scene.font3d_data print(f"UNREGISTER {bl_info['name']}") diff --git a/butils.py b/butils.py index 598db01..da33af4 100644 --- a/butils.py +++ b/butils.py @@ -2,6 +2,7 @@ import bpy import mathutils import queue import importlib +import os # then import dependencies for our addon if "Font" in locals(): @@ -289,11 +290,7 @@ def find_font_face_object(font_obj, face_name): return face return None -def move_in_fontcollection(obj, fontcollection): - for c in obj.users_collection: - c.objects.unlink(obj) - if fontcollection.objects.find(obj.name) < 0: - fontcollection.objects.link(obj) +def move_in_fontcollection(obj, fontcollection, allow_duplicates=False): # parent nesting structure # the font object @@ -339,10 +336,105 @@ def move_in_fontcollection(obj, fontcollection): glyphs_obj["face_name"] = obj["face_name"] glyphs_obj["font_name"] = obj["font_name"] + def get_hash(o): + return hash(tuple(tuple(v.co) for v in o.data.vertices )) + + for other_obj in find_objects_by_custom_property(glyphs_obj.children, "glyph", obj["glyph"]): + if get_hash(other_obj) == get_hash(obj) and not allow_duplicates: + return other_obj + # and now parent it! if obj.parent != glyphs_obj: obj.parent = glyphs_obj + for c in obj.users_collection: + c.objects.unlink(obj) + if fontcollection.objects.find(obj.name) < 0: + fontcollection.objects.link(obj) + + return obj + +def load_font_from_filepath(filepath): + if not filepath.endswith(".glb") and not filepath.endswith(".gltf"): + ShowMessageBox(f"{bl_info['name']} Font loading error", 'ERROR', f"Filepath({filepath}) is not a *.glb or *.gltf file") + return False + + font3d_data = bpy.context.scene.font3d_data + allObjectsBefore = [] + for ob in bpy.data.objects: + allObjectsBefore.append(ob.name) + + bpy.ops.import_scene.gltf(filepath=filepath) + + fontcollection = bpy.data.collections.get("Font3D") + if fontcollection is None: + fontcollection = bpy.data.collections.new("Font3D") + + remove_list = [] + all_objects = [] + for o in bpy.data.objects: + all_objects.append(o) + print("all objects", len(all_objects)) + for o in all_objects: + if o.name not in allObjectsBefore: + # must be new + if ("glyph" in o.keys() + and "face_name" in o.keys() + and "font_name" in o.keys()): + print("adding glyph", o) + glyph_id = o["glyph"] + font_name = o["font_name"] + face_name = o["face_name"] + glyph_obj = move_in_fontcollection( + o, + fontcollection) + Font.add_glyph( + font_name, + face_name, + glyph_id, + glyph_obj) + if glyph_obj != o: + remove_list.append(o) + + found = False + for f in font3d_data.available_fonts.values(): + if f.font_name == font_name: + found = True + break + if not found: + f = font3d_data.available_fonts.add() + f.font_name = font_name + print(f"{__name__} added {font_name}") + else: + remove_list.append(o) + print("add to remove list", o) + for o in remove_list: + bpy.data.objects.remove(o, do_unlink=True) + print("removed",o) + print("butils:: should have been doing loading the fonts") + +def getPreferences(context): + preferences = context.preferences + return preferences.addons['font3d'].preferences + +# clear available fonts +def clear_available_fonts(): + bpy.context.scene.font3d_data.available_fonts.clear() + +def load_available_fonts(): + preferences = getPreferences(bpy.context) + + currentObjects = [] + for ob in bpy.data.objects: + currentObjects.append(ob.name) + + print(f"assets folder: {preferences.assets_dir}") + font_dir = f"{preferences.assets_dir}/fonts" + for file in os.listdir(font_dir): + if file.endswith(".glb") or file.endswith(".gltf"): + font_path = os.path.join(font_dir, file) + load_font_from_filepath(font_path) + def ShowMessageBox(title = "Message Box", icon = 'INFO', message=""): """Show a simple message box @@ -379,7 +471,6 @@ def ShowMessageBox(title = "Message Box", icon = 'INFO', message=""): bpy.context.window_manager.popup_menu(draw, title = title, icon = icon) def set_text_on_curve(text_properties): - print(f"set text on curve {utils.get_timestamp()} with {text_properties.letter_spacing} and {text_properties.get('letter_spacingor')}") mom = text_properties.text_object if mom.type != "CURVE": return False @@ -430,7 +521,8 @@ def set_text_on_curve(text_properties): if c == 'n': next_line_advance = get_next_line_advance(mom, advance, glyph_advance) if advance == next_line_advance: - self.report({'INFO'}, f"would like to add new line for {text_properties.text} please") + # self.report({'INFO'}, f"would like to add new line for {text_properties.text} please") + print(f"would like to add new line for {text_properties.text} please") advance = next_line_advance continue is_command = False @@ -443,7 +535,8 @@ def set_text_on_curve(text_properties): ob = None if regenerate: if glyph == None: - self.report({'ERROR'}, f"Glyph not found for {font_name} {font_face} {glyph_id}") + # self.report({'ERROR'}, f"Glyph not found for {font_name} {font_face} {glyph_id}") + print(f"Glyph not found for {font_name} {font_face} {glyph_id}") continue ob = bpy.data.objects.new(f"{glyph_id}", glyph.data) @@ -476,7 +569,10 @@ def set_text_on_curve(text_properties): if ob.rotation_mode != 'QUATERNION': ob.rotation_mode = 'QUATERNION' q = mathutils.Quaternion() - q.rotate(mathutils.Euler((radians(90),0,0))) + q.rotate(text_properties.orientation) + # mathutils.Euler((radians(text_properties.orientation.x), + # radians(text_properties.orientation.y), + # radians(text_properties.orientation.z)))) ob.rotation_quaternion = (mom.matrix_world @ motor[0] @ q.to_matrix().to_4x4()).to_quaternion() scalor = 0.001