only import on demand

This commit is contained in:
jrkb 2024-08-21 14:42:53 +02:00
parent e23369df94
commit 25ef83878a
4 changed files with 722 additions and 107 deletions

215
butils.py
View file

@ -314,7 +314,6 @@ def find_font_face_object(font_obj, face_name):
return None
def move_in_fontcollection(obj, fontcollection, allow_duplicates=False):
# parent nesting structure
# the font object
font_obj = find_font_object(fontcollection,
@ -377,80 +376,104 @@ def move_in_fontcollection(obj, fontcollection, allow_duplicates=False):
return obj
def load_font_from_filepath(filepath):
def register_font_from_filepath(filepath):
from .bimport import get_font_faces_in_file
availables = get_font_faces_in_file(filepath)
fonts = {}
for a in availables:
font_name = a["font_name"]
face_name = a["face_name"]
glyph = a["glyph"]
if not font_name in fonts:
fonts[font_name] = {}
if not face_name in fonts[font_name]:
fonts[font_name][face_name] = []
fonts[font_name][face_name].append(glyph)
for font_name in fonts:
for face_name in fonts[font_name]:
Font.register_font(font_name,
face_name,
fonts[font_name][face_name],
filepath)
def load_font_from_filepath(filepath, glyphs="", font_name="", face_name=""):
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
abc3d_data = bpy.context.scene.abc3d_data
allObjectsBefore = []
for ob in bpy.data.objects:
allObjectsBefore.append(ob.name)
bpy.ops.import_scene.gltf(filepath=filepath)
marker_property = "font_import"
bpy.ops.abc3d.import_font_gltf(filepath=filepath,
glyphs=glyphs,
marker_property=marker_property,
font_name=font_name,
face_name=face_name)
fontcollection = bpy.data.collections.get("ABC3D")
if fontcollection is None:
fontcollection = bpy.data.collections.new("ABC3D")
modified_font_faces = []
all_glyph_os = []
remove_list = []
all_objects = []
for o in bpy.data.objects:
all_objects.append(o)
for o in all_objects:
o_exists = True
try:
o, o.name
except ReferenceError as e:
o_exists = False
if o_exists and 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()
and not ("type" in o.keys() and o["type"] == "metrics")
and not is_metrics_object(o)
):
glyph_id = o["glyph"]
font_name = o["font_name"]
face_name = o["face_name"]
# ShowMessageBox("Loading Font", "INFO", f"adding glyph {glyph_id} for {font_name} {face_name}")
print(f"adding glyph {glyph_id} for {font_name} {face_name}")
glyph_obj = move_in_fontcollection(
o,
fontcollection)
Font.add_glyph(
font_name,
face_name,
glyph_id,
glyph_obj)
for c in o.children:
if is_metrics_object(c):
add_metrics_obj_from_bound_box(glyph_obj,
bound_box_as_array(c.bound_box))
if glyph_obj != o:
remove_list.append(o)
# found = False
# for f in abc3d_data.available_fonts.values():
# print(f"has in availables {f.font_name} {f.face_name}")
# if f.font_name == font_name and f.face_name == face_name:
# found = True
# break
# if not found:
# f = abc3d_data.available_fonts.add()
# f.font_name = font_name
# f.face_name = face_name
# print(f"{__name__} added {font_name} {face_name}")
elif o_exists:
for o in bpy.context.scene.objects:
if marker_property in o:
if "type" in o and o["type"] == "glyph":
all_glyph_os.append(o)
else:
remove_list.append(o)
for o in remove_list:
try:
bpy.data.objects.remove(o, do_unlink=True)
except ReferenceError as e:
print(f"{__name__} could not remove object, because it doesn't exist")
print(f"{__name__}: loaded font from {filepath}")
for o in all_glyph_os:
glyph_id = o["glyph"]
font_name = o["font_name"]
face_name = o["face_name"]
del o[marker_property]
glyph_obj = move_in_fontcollection(
o,
fontcollection)
Font.add_glyph(
font_name,
face_name,
glyph_id,
glyph_obj)
for c in o.children:
if is_metrics_object(c):
add_metrics_obj_from_bound_box(glyph_obj,
bound_box_as_array(c.bound_box))
modified_font_faces.append({"font_name": font_name,
"face_name": face_name})
if glyph_obj != o:
remove_list.append(o)
for mff in modified_font_faces:
glyphs = []
face = Font.fonts[mff["font_name"]].faces[mff["face_name"]]
# iterate glyphs
for g in face.glyphs:
# iterate alternates
for glyph in face.glyphs[g]:
glyphs.append(glyph)
if len(glyphs) > 0:
add_default_metrics_to_objects(glyphs)
# calculate unit factor
h = get_glyph_height(glyphs[0])
if h != 0:
face.unit_factor = 1 / h
update_available_fonts()
remove_list = []
for o in bpy.context.scene.collection.all_objects:
if not o.name in fontcollection.all_objects:
if marker_property in o and o[marker_property] == True:
remove_list.append(o)
simply_delete_objects(remove_list)
# completely_delete_objects(remove_list)
def update_available_fonts():
abc3d_data = bpy.context.scene.abc3d_data
@ -491,11 +514,24 @@ def load_installed_fonts():
if file.endswith(".glb") or file.endswith(".gltf"):
font_path = os.path.join(font_dir, file)
# ShowMessageBox("Loading Font", "INFO", f"loading font from {font_path}")
print(f"loading font from {font_path}")
for f in bpy.context.scene.abc3d_data.available_fonts.values():
print(f"available font: {f.font_name} {f.face_name}")
# print(f"loading font from {font_path}")
# for f in bpy.context.scene.abc3d_data.available_fonts.values():
# print(f"available font: {f.font_name} {f.face_name}")
register_font_from_filepath(font_path)
load_font_from_filepath(font_path)
def register_installed_fonts():
preferences = getPreferences(bpy.context)
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)
# ShowMessageBox("Loading Font", "INFO", f"loading font from {font_path}")
# print(f"loading font from {font_path}")
# for f in bpy.context.scene.abc3d_data.available_fonts.values():
# print(f"available font: {f.font_name} {f.face_name}")
register_font_from_filepath(font_path)
def ShowMessageBox(title = "Message Box", icon = 'INFO', message=""):
"""Show a simple message box
@ -531,12 +567,15 @@ def ShowMessageBox(title = "Message Box", icon = 'INFO', message=""):
self.layout.label(text=n)
bpy.context.window_manager.popup_menu(draw, title = title, icon = icon)
def completely_delete_objects(objs):
def simply_delete_objects(objs):
context_override = bpy.context.copy()
context_override["selected_objects"] = list(objs)
with bpy.context.temp_override(**context_override):
bpy.ops.object.delete()
def completely_delete_objects(objs):
simply_delete_objects(objs)
# remove deleted objects
# this is necessary
for g in objs:
@ -578,7 +617,23 @@ def get_glyph_advance(glyph_obj):
return abs(c.bound_box[4][0] - c.bound_box[0][0])
return abs(glyph_obj.bound_box[4][0] - glyph_obj.bound_box[0][0])
def set_text_on_curve(text_properties):
def get_glyph_height(glyph_obj):
for c in glyph_obj.children:
if is_metrics_object(c):
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):
loaded, missing, loadable, files = Font.test_glyphs_availability(
font_name,
face_name,
text)
if len(loadable) > 0:
for filepath in files:
load_font_from_filepath(filepath, loadable, font_name, face_name)
return True
def set_text_on_curve(text_properties, recursive=True):
# starttime = time.perf_counter_ns()
mom = text_properties.text_object
if mom.type != "CURVE":
@ -605,6 +660,22 @@ def set_text_on_curve(text_properties):
# if we regenerate.... delete objects
if regenerate:
# loaded, missing, maybe, files = Font.test_glyphs_availability(
# text_properties.font_name,
# text_properties.face_name,
# text_properties.text)
# if len(maybe) > 0 and recursive:
# print(f"doing the thing {len(files)} times")
# for filepath in files:
# def loader():
# set_text_on_curve(text_properties, False)
# print(f"loading font from filepath {filepath} {maybe}")
# load_font_from_filepath(filepath, maybe)
# print(f"font: {text_properties.font_name} face: {text_properties.face_name}")
# print("text",text_properties.text)
# text_properties.font_size = text_properties.font_size
# # run_in_main_thread(loader)
# return
completely_delete_objects(glyph_objects)
# context_override = bpy.context.copy()
# context_override["selected_objects"] = list(glyph_objects)
@ -696,7 +767,8 @@ def set_text_on_curve(text_properties):
ob.rotation_quaternion = q
# ob.rotation_quaternion = (mom.matrix_world @ q.to_matrix().to_4x4()).to_quaternion()
scalor = 0.001 * text_properties.font_size
face = Font.fonts[text_properties.font_name].faces[text_properties.face_name]
scalor = face.unit_factor * text_properties.font_size
glyph_advance = get_glyph_advance(glyph) * scalor + text_properties.letter_spacing
@ -929,6 +1001,13 @@ def get_metrics_bound_box(bb, bb_uebermetrics):
metrics[7][0] = bb[7][0]
return metrics
def get_metrics_object(o):
if is_glyph(o):
for c in o.children:
if is_metrics_object(c):
return c
return None
def add_default_metrics_to_objects(objects=None, overwrite_existing=False):
if type(objects) == type(None):
objects=bpy.context.selected_objects