diff --git a/README.md b/README.md index 9e500d6..9b5d420 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ / ___ \| |_) | |___ ___) | |_| | /_/ \_\____/ \____|____/|____/ ``` -v0.0.4 Convenience tool to work with 3D typography in Blender and Cinema4D. diff --git a/__init__.py b/__init__.py index b3ca721..3fe519a 100644 --- a/__init__.py +++ b/__init__.py @@ -15,7 +15,7 @@ import importlib bl_info = { "name": "ABC3D", "author": "Jakob Schlötter, Studio Pointer*", - "version": (0, 0, 4), + "version": (0, 0, 3), "blender": (4, 1, 0), "location": "VIEW3D", "description": "Convenience addon for 3D fonts", @@ -242,6 +242,9 @@ class ABC3D_text_properties(bpy.types.PropertyGroup): distribution_type: bpy.props.StringProperty() glyphs: bpy.props.CollectionProperty(type=ABC3D_glyph_properties) +# TODO: simply, merge, cut cut cut + + class ABC3D_data(bpy.types.PropertyGroup): available_fonts: bpy.props.CollectionProperty( type=ABC3D_available_font, name="Available fonts") @@ -1560,8 +1563,8 @@ def on_depsgraph_update(scene, depsgraph): butils.run_in_main_thread(later) + def register(): - print(f"REGISTER {utils.prefix()}") addon_updater_ops.register(bl_info) for cls in classes: @@ -1569,8 +1572,9 @@ def register(): bpy.utils.register_class(cls) bpy.types.Scene.abc3d_data = bpy.props.PointerProperty(type=ABC3D_data) # bpy.types.Object.__del__ = lambda self: print(f"Bye {self.name}") + print(f"REGISTER {bl_info['name']}") - # autostart if we load a blend file + # auto start if we load a blend file if load_handler not in bpy.app.handlers.load_post: bpy.app.handlers.load_post.append(load_handler) # and autostart if we reload script @@ -1589,7 +1593,7 @@ def register(): # bpy.ops.abc3d.load_installed_fonts() - Font.init() + Font.name_to_glyph_d = Font.generate_name_to_glyph_d() def unregister(): @@ -1611,7 +1615,7 @@ def unregister(): bpy.app.handlers.depsgraph_update_post.remove(on_depsgraph_update) del bpy.types.Scene.abc3d_data - print(f"UNREGISTER {utils.prefix()}") + print(f"UNREGISTER {bl_info['name']}") if __name__ == '__main__': diff --git a/butils.py b/butils.py index b9488ba..b3b5e00 100644 --- a/butils.py +++ b/butils.py @@ -553,9 +553,7 @@ def register_installed_fonts(): # print(f"available font: {f.font_name} {f.face_name}") register_font_from_filepath(font_path) -message_memory = [] - -def ShowMessageBox(title = "Message Box", icon = 'INFO', message="", prevent_repeat=False): +def ShowMessageBox(title = "Message Box", icon = 'INFO', message=""): """Show a simple message box @@ -581,13 +579,6 @@ def ShowMessageBox(title = "Message Box", icon = 'INFO', message="", prevent_rep butils.ShowMessageBox(title="",message=("AAAAAH","NOOOOO"),icon=) """ - global message_memory - if prevent_repeat: - for m in message_memory: - if m[0] == title and m[1] == icon and m[2] == message: - print("PREVENT PREVENT") - return - message_memory.append([title, icon, message]) myLines=message def draw(self, context): if isinstance(myLines, str): @@ -674,21 +665,11 @@ def get_glyph_height(glyph_obj): return abs(c.bound_box[0][1] - c.bound_box[3][1]) return abs(glyph_obj.bound_box[0][1] - glyph_obj.bound_box[3][1]) -def prepare_text(font_name, face_name, text, allow_replacement=True): +def prepare_text(font_name, face_name, text): loaded, missing, loadable, files = Font.test_glyphs_availability( font_name, face_name, text) - # possibly replace upper and lower case letters with each other - if len(missing) > 0 and allow_replacement: - replacement_search = "" - for m in missing: - if m.isalpha(): - replacement_search += m.swapcase() - r = Font.test_availability(font_name, face_name, replacement_search) - loadable += r["maybe"] - # not update (loaded, missing, files), we only use loadable/maybe later - if len(loadable) > 0: for filepath in files: load_font_from_filepath(filepath, loadable, font_name, face_name) @@ -780,6 +761,9 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4) if c == '\\': is_command = True continue + if c == ' ': + advance = advance + scalor + continue is_newline = False if is_command: if c == 'n': @@ -794,33 +778,14 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4) is_command = False glyph_id = c - glyph_tmp = Font.get_glyph(text_properties.font_name, + glyph = Font.get_glyph(text_properties.font_name, text_properties.face_name, - glyph_id) - if glyph_tmp == None: - space_width = Font.is_space(glyph_id) - if space_width != False: - advance = advance + space_width * text_properties.font_size - continue + glyph_id).original - message=f"Glyph not found for font_name='{text_properties.font_name}' face_name='{text_properties.face_name}' glyph_id='{glyph_id}'" - replaced = False - if glyph_id.isalpha(): - possible_replacement = glyph_id.swapcase() - glyph_tmp = Font.get_glyph(text_properties.font_name, - text_properties.face_name, - possible_replacement) - if glyph_tmp != None: - message = message + f" (replaced with '{possible_replacement}')" - replaced = True - - ShowMessageBox(title="Glyph replaced" if replaced else "Glyph missing", - icon='INFO' if replaced else 'ERROR', - message=message, - prevent_repeat=True) - if replaced == False: - continue - glyph = glyph_tmp.original + if glyph == None: + # self.report({'ERROR'}, f"Glyph not found for {font_name} {face_name} {glyph_id}") + print(f"Glyph not found for {text_properties.font_name} {text_properties.face_name} {glyph_id}") + continue ob = None obg = None @@ -847,15 +812,6 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4) ob.constraints["Follow Path"].up_axis = "UP_Y" spline_index = 0 elif distribution_type == 'CALCULATE': - previous_ob_rotation_mode = None - previous_obg_rotation_mode = None - if ob.rotation_mode != 'QUATERNION': - ob.rotation_mode = 'QUATERNION' - previous_ob_rotation_mode = ob.rotation_mode - if obg.rotation_mode != 'QUATERNION': - obg.rotation_mode = 'QUATERNION' - previous_obg_rotation_mode = obg.rotation_mode - location, tangent, spline_index = calc_point_on_bezier_curve(mom, advance, True, True) if spline_index != previous_spline_index: is_newline = True @@ -881,7 +837,10 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4) vectors, factors, local_main_axis) - + if ob.rotation_mode != 'QUATERNION': + ob.rotation_mode = 'QUATERNION' + if obg.rotation_mode != 'QUATERNION': + obg.rotation_mode = 'QUATERNION' q = mathutils.Quaternion() q.rotate(text_properties.orientation) if regenerate: @@ -896,10 +855,6 @@ def set_text_on_curve(text_properties, reset_timeout_s=0.1, reset_depsgraph_n=4) obg.rotation_quaternion = (mom.matrix_world @ q.to_matrix().to_4x4()).to_quaternion() # ob.rotation_quaternion = (mom.matrix_world @ q.to_matrix().to_4x4()).to_quaternion() - if previous_ob_rotation_mode: - ob.rotation_mode = previous_ob_rotation_mode - if previous_obg_rotation_mode: - obg.rotation_mode = previous_obg_rotation_mode glyph_advance = get_glyph_advance(glyph) * scalor + text_properties.letter_spacing diff --git a/common/Font.py b/common/Font.py index 1c8368e..aa936db 100644 --- a/common/Font.py +++ b/common/Font.py @@ -37,8 +37,6 @@ name_to_glyph_d = { "space": " ", } -space_d = {} - known_misspellings = { # simple misspelling "excent" : "accent", @@ -76,44 +74,17 @@ def name_to_glyph(name): else: return None - -def is_space(character): - for name in space_d: - if character == space_d[name][0]: - return space_d[name][1] - return False - - -def generate_from_file_d(filepath): +def generate_name_to_glyph_d(): d = {} - with open(filepath) as f: + with open(f"{Path(__file__).parent}/glyphNamesToUnicode.txt") as f: for line in f: if line[0] == '#': continue - split = line.split(' ') - if len(split) == 2: - (name, hexstr) = line.split(' ') - val = chr(int(hexstr, base=16)) - d[name] = val - if len(split) == 3: - # we might have a parameter, like for the spaces - (name, hexstr, parameter) = line.split(' ') - parameter_value = float(parameter) - val = chr(int(hexstr, base=16)) - d[name] = [val, parameter_value] + (name, hexstr) = line.split(' ') + val = chr(int(hexstr, base=16)) + d[name] = val return d -def generate_name_to_glyph_d(): - return generate_from_file_d(f"{Path(__file__).parent}/glyphNamesToUnicode.txt") - -def generate_space_d(): - return generate_from_file_d(f"{Path(__file__).parent}/spacesUnicode.txt") - -def init(): - global name_to_glyph_d - global space_d - name_to_glyph_d = generate_name_to_glyph_d() - space_d = generate_space_d() class FontFace: """FontFace is a class holding glyphs @@ -203,19 +174,19 @@ def get_glyph(font_name, face_name, glyph_id, alternate=0): """ if not fonts.keys().__contains__(font_name): - # print(f"ABC3D::get_glyph: font name({font_name}) not found") - # print(fonts.keys()) + print(f"ABC3D::get_glyph: font name({font_name}) not found") + print(fonts.keys()) return None face = fonts[font_name].faces.get(face_name) if face == None: - # print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) not found") - # print(fonts[font_name].faces.keys()) + print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) not found") + print(fonts[font_name].faces.keys()) return None glyphs_for_id = face.glyphs.get(glyph_id) if glyphs_for_id == None or len(glyphs_for_id) <= alternate: - # print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) glyph({glyph_id})[{alternate}] not found") + print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) glyph({glyph_id})[{alternate}] not found") if glyph_id not in fonts[font_name].faces[face_name].missing_glyphs: fonts[font_name].faces[face_name].missing_glyphs.append(glyph_id) return None diff --git a/common/spacesUnicode.txt b/common/spacesUnicode.txt deleted file mode 100644 index da6a7c9..0000000 --- a/common/spacesUnicode.txt +++ /dev/null @@ -1,23 +0,0 @@ -# The space value derives from The Elements of Typographic Style -# same for en-/em values. Rest are rough guesses. -space 0020 0.25 -nbspace 00A0 0.25 -# ethi:wordspace 1361 # NOTE: has shape -enquad 2000 0.5 -emquad 2001 1 -enspace 2002 0.5 -emspace 2003 1 -threeperemspace 2004 3 -fourperemspace 2005 4 -sixperemspace 2006 6 -figurespace 2007 1 -punctuationspace 2008 1 -thinspace 2009 0.1 -hairspace 200A 0.05 -zerowidthspace 200B 0 -narrownobreakspace 202F 0.1 -mediummathematicalspace 205F 1 -cntr:space 2420 0.25 -ideographicspace 3000 1 -# ideographichalffillspace 303F # NOTE: has shape -zerowidthnobreakspace FEFF 0 diff --git a/common/utils.py b/common/utils.py index 5a23e78..1e815e8 100644 --- a/common/utils.py +++ b/common/utils.py @@ -4,7 +4,7 @@ def get_version_major(): def get_version_minor(): return 0 def get_version_patch(): - return 4 + return 3 def get_version_string(): return f"{get_version_major()}.{get_version_minor()}.{get_version_patch}" def prefix(): @@ -72,10 +72,6 @@ def printerr(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) -def removeNonAlphabetic(s): - return ''.join([i for i in s if i.isalpha()]) - - # # 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 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index fcb9ea9..0000000 --- a/requirements.txt +++ /dev/null @@ -1,33 +0,0 @@ -astroid==3.3.5 -attrs==24.2.0 -black==24.10.0 -bpy==4.2.0 -cattrs==24.1.2 -certifi==2024.8.30 -charset-normalizer==3.4.0 -click==8.1.7 -Cython==3.0.11 -dill==0.3.9 -docstring-to-markdown==0.15 -flake8==7.1.1 -idna==3.10 -isort==5.13.2 -jedi==0.19.1 -jedi-language-server==0.41.4 -lsprotocol==2023.0.1 -mathutils==3.3.0 -mccabe==0.7.0 -mypy-extensions==1.0.0 -numpy==2.1.3 -packaging==24.1 -parso==0.8.4 -pathspec==0.12.1 -platformdirs==4.3.6 -pycodestyle==2.12.1 -pyflakes==3.2.0 -pygls==1.3.1 -pylint==3.3.1 -requests==2.32.3 -tomlkit==0.13.2 -urllib3==2.2.3 -zstandard==0.23.0