instantiate an A
This commit is contained in:
parent
64db7af544
commit
d06bf038b0
6 changed files with 352 additions and 22 deletions
|
@ -16,3 +16,6 @@ ln -s $HOME/git/pointer/neomatter/font3d/font3d_blender_addon $HOME/git/tools/bl
|
||||||
bpy.utils.script_paths()
|
bpy.utils.script_paths()
|
||||||
```
|
```
|
||||||
then check it for the `addons` directory
|
then check it for the `addons` directory
|
||||||
|
|
||||||
|
# reload addon in blender:
|
||||||
|
F3 -> "reload scripts"
|
||||||
|
|
195
__init__.py
195
__init__.py
|
@ -14,6 +14,22 @@ bl_info = {
|
||||||
"category": "Typography",
|
"category": "Typography",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# make sure that modules are reloadable
|
||||||
|
# when registering
|
||||||
|
# handy for development
|
||||||
|
# first import dependencies for the method
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
# then import dependencies for our addon
|
||||||
|
if "bpy" in locals():
|
||||||
|
importlib.reload(Font)
|
||||||
|
importlib.reload(utils)
|
||||||
|
importlib.reload(butils)
|
||||||
|
else:
|
||||||
|
from .common import Font
|
||||||
|
from .common import utils
|
||||||
|
from . import butils
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import math
|
import math
|
||||||
import io
|
import io
|
||||||
|
@ -25,25 +41,18 @@ from random import uniform
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
def get_timestamp():
|
import re
|
||||||
return datetime.datetime.fromtimestamp(time.time()).strftime('%Y.%m.%d-%H:%M:%S')
|
|
||||||
|
|
||||||
class SharedVariables():
|
class SharedVariables():
|
||||||
fonts: dict = {}
|
fonts = Font.fonts
|
||||||
|
|
||||||
def __init__(self, **kv):
|
def __init__(self, **kv):
|
||||||
self.__dict__.update(kv)
|
self.__dict__.update(kv)
|
||||||
|
|
||||||
|
|
||||||
shared = SharedVariables()
|
shared = SharedVariables()
|
||||||
|
|
||||||
def mapRange(in_value, in_min, in_max, out_min, out_max, clamp=False):
|
|
||||||
output = out_min + ((out_max - out_min) / (in_max - in_min)) * (in_value - in_min)
|
|
||||||
if clamp:
|
|
||||||
if out_min < out_max:
|
|
||||||
return min(out_max, max(out_min, output))
|
|
||||||
else:
|
|
||||||
return max(out_max, min(out_min, output))
|
|
||||||
else:
|
|
||||||
return output
|
|
||||||
|
|
||||||
class FONT3D_OT_Font3D(bpy.types.Operator):
|
class FONT3D_OT_Font3D(bpy.types.Operator):
|
||||||
"""Font 3D"""
|
"""Font 3D"""
|
||||||
|
@ -66,10 +75,36 @@ class FONT3D_OT_Font3D(bpy.types.Operator):
|
||||||
|
|
||||||
class FONT3D_settings(bpy.types.PropertyGroup):
|
class FONT3D_settings(bpy.types.PropertyGroup):
|
||||||
font_path: bpy.props.StringProperty(name="Font path",
|
font_path: bpy.props.StringProperty(name="Font path",
|
||||||
description="Where is the font",
|
description="Where is the font",
|
||||||
default="",
|
default="",
|
||||||
maxlen=1024,
|
maxlen=1024,
|
||||||
subtype="FILE_PATH")
|
subtype="FILE_PATH")
|
||||||
|
import_infix: bpy.props.StringProperty(name="Font name import infix",
|
||||||
|
description="The infix which all font objects to import have",
|
||||||
|
default="_NM_",
|
||||||
|
maxlen=1024,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FONT3D_available_font(bpy.types.PropertyGroup):
|
||||||
|
font_name: bpy.props.StringProperty(name="whatever")
|
||||||
|
|
||||||
|
#TODO: simply, merge, cut cut cut
|
||||||
|
class FONT3D_data(bpy.types.PropertyGroup):
|
||||||
|
available_fonts: bpy.props.CollectionProperty(type=FONT3D_available_font, name="name of the collection poporotery")
|
||||||
|
active_font_index: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
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):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FONT3D_PT_panel(bpy.types.Panel):
|
class FONT3D_PT_panel(bpy.types.Panel):
|
||||||
bl_label = "Panel for Font3D"
|
bl_label = "Panel for Font3D"
|
||||||
|
@ -78,16 +113,26 @@ class FONT3D_PT_panel(bpy.types.Panel):
|
||||||
bl_region_type = "UI"
|
bl_region_type = "UI"
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
|
global shared
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
|
|
||||||
font3d = scene.font3d
|
font3d = scene.font3d
|
||||||
|
font3d_data = scene.font3d_data
|
||||||
|
|
||||||
layout.label(text="Load FontFile:")
|
layout.label(text="Load FontFile:")
|
||||||
layout.row().prop(font3d, "font_path")
|
layout.row().prop(font3d, "font_path")
|
||||||
layout.row().operator('font3d.loadfont', text='Load Font')
|
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.label(text='DEBUG')
|
||||||
layout.row().operator('font3d.testfont', text='Test Font')
|
layout.row().operator('font3d.testfont', text='Test Font')
|
||||||
|
layout.row().prop(font3d, "import_infix")
|
||||||
|
layout.row().operator('font3d.create_font_from_objects', text='Create Font')
|
||||||
|
layout.row().operator('font3d.toggle_font3d_collection', text='Toggle Collection')
|
||||||
|
layout.label(text='DEBUG END')
|
||||||
|
|
||||||
|
|
||||||
class FONT3D_OT_LoadFont(bpy.types.Operator):
|
class FONT3D_OT_LoadFont(bpy.types.Operator):
|
||||||
"""Load Font 3D"""
|
"""Load Font 3D"""
|
||||||
|
@ -99,7 +144,7 @@ class FONT3D_OT_LoadFont(bpy.types.Operator):
|
||||||
global shared
|
global shared
|
||||||
scene = bpy.context.scene
|
scene = bpy.context.scene
|
||||||
|
|
||||||
print(f"loading da font at path {scene.font3d.font_path}")
|
# print(f"loading da font at path {scene.font3d.font_path}")
|
||||||
|
|
||||||
currentObjects = []
|
currentObjects = []
|
||||||
for ob in bpy.data.objects:
|
for ob in bpy.data.objects:
|
||||||
|
@ -119,10 +164,8 @@ class FONT3D_OT_LoadFont(bpy.types.Operator):
|
||||||
for o in bpy.data.objects:
|
for o in bpy.data.objects:
|
||||||
if o.name not in currentObjects:
|
if o.name not in currentObjects:
|
||||||
if (o.parent == None):
|
if (o.parent == None):
|
||||||
print(f"found root node --> {o.name}")
|
|
||||||
font['name'] = o.name
|
font['name'] = o.name
|
||||||
elif o.parent.name.startswith("glyphs"):
|
elif o.parent.name.startswith("glyphs"):
|
||||||
print(f"loading glyph --> {o.name}")
|
|
||||||
font['glyphs'].append(o)
|
font['glyphs'].append(o)
|
||||||
newObjects.append(o.name)
|
newObjects.append(o.name)
|
||||||
scene.collection.objects.unlink(o)
|
scene.collection.objects.unlink(o)
|
||||||
|
@ -132,7 +175,8 @@ class FONT3D_OT_LoadFont(bpy.types.Operator):
|
||||||
shared.fonts
|
shared.fonts
|
||||||
except:
|
except:
|
||||||
shared.fonts = {}
|
shared.fonts = {}
|
||||||
shared.fonts[font['name']] = font
|
shared.fonts[font['name']] = Font.Font()
|
||||||
|
shared.fonts[font['name']]['faces']['regular'] = font
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
@ -146,22 +190,127 @@ class FONT3D_OT_TestFont(bpy.types.Operator):
|
||||||
global shared
|
global shared
|
||||||
scene = bpy.context.scene
|
scene = bpy.context.scene
|
||||||
|
|
||||||
print(shared.fonts)
|
|
||||||
|
selected = bpy.context.view_layer.objects.active
|
||||||
|
|
||||||
|
glyph = Font.get_glyph("NM_Origin", "Tender", "A").data
|
||||||
|
ob = bpy.data.objects.new('Duplicate_Linked', glyph)
|
||||||
|
ob.location = selected.location
|
||||||
|
ob.scale = (0.01, 0.01, 0.01)
|
||||||
|
selected.users_collection[0].objects.link(ob)
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class FONT3D_OT_ToggleFont3DCollection(bpy.types.Operator):
|
||||||
|
"""Toggle Font3D Collection"""
|
||||||
|
bl_idname = "font3d.toggle_font3d_collection"
|
||||||
|
bl_label = "Toggle Collection visibility"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
scene = context.scene
|
||||||
|
fontcollection = bpy.data.collections.get("Font3D")
|
||||||
|
|
||||||
|
if fontcollection is None:
|
||||||
|
self.report({'INFO'}, f"{bl_info['name']}: There is no collection")
|
||||||
|
elif scene.collection.children.find(fontcollection.name) < 0:
|
||||||
|
scene.collection.children.link(fontcollection)
|
||||||
|
self.report({'INFO'}, f"{bl_info['name']}: show collection")
|
||||||
|
else:
|
||||||
|
scene.collection.children.unlink(fontcollection)
|
||||||
|
self.report({'INFO'}, f"{bl_info['name']}: hide collection")
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class FONT3D_OT_CreateFontFromObjects(bpy.types.Operator):
|
||||||
|
"""Create Font from open objects"""
|
||||||
|
bl_idname = "font3d.create_font_from_objects"
|
||||||
|
bl_label = "Create Font"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
global shared
|
||||||
|
scene = bpy.context.scene
|
||||||
|
font3d = scene.font3d
|
||||||
|
font3d_data = scene.font3d_data
|
||||||
|
|
||||||
|
fontcollection = bpy.data.collections.get("Font3D")
|
||||||
|
|
||||||
|
if fontcollection is None:
|
||||||
|
fontcollection = bpy.data.collections.new("Font3D")
|
||||||
|
|
||||||
|
ifxsplit = font3d.import_infix.split('_')
|
||||||
|
font_name = f"{ifxsplit[1]}_{ifxsplit[2]}"
|
||||||
|
face_name = ifxsplit[3]
|
||||||
|
|
||||||
|
added_font = False
|
||||||
|
|
||||||
|
font3d_data.available_fonts.clear()
|
||||||
|
|
||||||
|
currentObjects = []
|
||||||
|
for o in bpy.data.objects:
|
||||||
|
if o.name not in currentObjects:
|
||||||
|
if font3d.import_infix in o.name:
|
||||||
|
uc = o.users_collection
|
||||||
|
regex = f"{font3d.import_infix}(.)*"
|
||||||
|
name = re.sub(regex, "", o.name)
|
||||||
|
glyph_id = "unknown"
|
||||||
|
if len(name) == 1:
|
||||||
|
glyph_id = name
|
||||||
|
elif name in Font.name_to_glyph_d:
|
||||||
|
glyph_id = Font.name_to_glyph_d[name]
|
||||||
|
|
||||||
|
if glyph_id != "unknown":
|
||||||
|
bpy.data.objects[o.name]["glyph"] = glyph_id
|
||||||
|
butils.move_in_fontcollection(
|
||||||
|
o,
|
||||||
|
fontcollection,
|
||||||
|
scene)
|
||||||
|
Font.add_glyph(
|
||||||
|
font_name,
|
||||||
|
face_name,
|
||||||
|
glyph_id,
|
||||||
|
o)
|
||||||
|
added_font = True
|
||||||
|
|
||||||
|
#TODO: is there a better way to iterate over a CollectionProperty?
|
||||||
|
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
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.report({'INFO'}, f"did not understand glyph {name}")
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
FONT3D_OT_Font3D,
|
FONT3D_OT_Font3D,
|
||||||
|
FONT3D_available_font,
|
||||||
|
FONT3D_data,
|
||||||
FONT3D_settings,
|
FONT3D_settings,
|
||||||
|
FONT3D_UL_fonts,
|
||||||
FONT3D_PT_panel,
|
FONT3D_PT_panel,
|
||||||
FONT3D_OT_TestFont,
|
FONT3D_OT_TestFont,
|
||||||
FONT3D_OT_LoadFont
|
FONT3D_OT_LoadFont,
|
||||||
|
FONT3D_OT_ToggleFont3DCollection,
|
||||||
|
FONT3D_OT_CreateFontFromObjects,
|
||||||
)
|
)
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
bpy.types.Scene.font3d = bpy.props.PointerProperty(type=FONT3D_settings)
|
bpy.types.Scene.font3d = bpy.props.PointerProperty(type=FONT3D_settings)
|
||||||
|
bpy.types.Scene.font3d_data = bpy.props.PointerProperty(type=FONT3D_data)
|
||||||
|
print(f"REGISTER {bl_info['name']}")
|
||||||
|
|
||||||
|
print(utils.get_timestamp())
|
||||||
|
print(shared.fonts)
|
||||||
# would love to properly auto start this, but IT DOES NOT WORK
|
# would love to properly auto start this, but IT DOES NOT WORK
|
||||||
# if load_handler not in bpy.app.handlers.load_post:
|
# if load_handler not in bpy.app.handlers.load_post:
|
||||||
# bpy.app.handlers.load_post.append(load_handler)
|
# bpy.app.handlers.load_post.append(load_handler)
|
||||||
|
@ -174,6 +323,8 @@ def unregister():
|
||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
|
|
||||||
del bpy.types.Scene.font3d
|
del bpy.types.Scene.font3d
|
||||||
|
del bpy.types.Scene.font3d_data
|
||||||
|
print(f"UNREGISTER {bl_info['name']}")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
register()
|
register()
|
||||||
|
|
|
@ -6,4 +6,12 @@ let g:jedi#environment_path = "venv"
|
||||||
|
|
||||||
""""""""""""""""""""""""""""""""" ALE
|
""""""""""""""""""""""""""""""""" ALE
|
||||||
|
|
||||||
|
"let g:ale_python_pylint_executable = '/home/jrkb/git/pointer/neomatter/font3d/font3d_blender_addon/venv/bin/pylint'
|
||||||
|
"let g:ale_python_executable='/home/jrkb/git/pointer/neomatter/font3d/font3d_blender_addon/venv/bin/python'
|
||||||
|
"let g:ale_python_pylint_use_global=1
|
||||||
|
"let g:ale_use_global_executables=1
|
||||||
|
"let g:ale_python_auto_pipenv=1
|
||||||
|
"let g:ale_python_auto_virtualenv=1
|
||||||
|
"let g:ale_virtualenv_dir_names = ['venv']
|
||||||
|
|
||||||
let g:ale_pattern_options = {'\.py$': {'ale_enabled': 0}}
|
let g:ale_pattern_options = {'\.py$': {'ale_enabled': 0}}
|
||||||
|
|
32
butils.py
Normal file
32
butils.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
|
||||||
|
def get_parent_collection_names(collection, parent_names):
|
||||||
|
for parent_collection in bpy.data.collections:
|
||||||
|
if collection.name in parent_collection.children.keys():
|
||||||
|
parent_names.append(parent_collection.name)
|
||||||
|
get_parent_collection_names(parent_collection, parent_names)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def turn_collection_hierarchy_into_path(obj):
|
||||||
|
parent_collection = obj.users_collection[0]
|
||||||
|
parent_names = []
|
||||||
|
parent_names.append(parent_collection.name)
|
||||||
|
get_parent_collection_names(parent_collection, parent_names)
|
||||||
|
parent_names.reverse()
|
||||||
|
return '\\'.join(parent_names)
|
||||||
|
|
||||||
|
def move_in_fontcollection(obj, fontcollection, scene):
|
||||||
|
# print(turn_collection_hierarchy_into_path(obj))
|
||||||
|
if scene.collection.objects.find(obj.name) >= 0:
|
||||||
|
scene.collection.objects.unlink(obj)
|
||||||
|
if fontcollection.objects.find(obj.name) < 0:
|
||||||
|
fontcollection.objects.link(obj)
|
||||||
|
if fontcollection.objects.find("glyphs") < 0:
|
||||||
|
empty = bpy.data.objects.new("glyphs", None)
|
||||||
|
empty.empty_display_type = 'PLAIN_AXES'
|
||||||
|
fontcollection.objects.link(empty)
|
||||||
|
glyphs = fontcollection.objects.get("glyphs")
|
||||||
|
if obj.parent != glyphs:
|
||||||
|
obj.parent = glyphs
|
118
common/Font.py
Normal file
118
common/Font.py
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
from typing import TypedDict
|
||||||
|
from typing import Dict
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
# convenience dictionary for translating names to glyph ids
|
||||||
|
name_to_glyph_d = {
|
||||||
|
"zero": "0",
|
||||||
|
"one": "1",
|
||||||
|
"two": "2",
|
||||||
|
"three": "3",
|
||||||
|
"four": "4",
|
||||||
|
"five": "5",
|
||||||
|
"six": "6",
|
||||||
|
"seven": "7",
|
||||||
|
"eight": "8",
|
||||||
|
"nine": "9",
|
||||||
|
"ampersand": "&",
|
||||||
|
"backslash": "\\",
|
||||||
|
"colon": ":",
|
||||||
|
"comma": ",",
|
||||||
|
"equal": "=",
|
||||||
|
"exclam": "!",
|
||||||
|
"hyphen": "-",
|
||||||
|
"minus": "−",
|
||||||
|
"parenleft": "(",
|
||||||
|
"parenright": "(",
|
||||||
|
"period": ".",
|
||||||
|
"plus": "+",
|
||||||
|
"question": "?",
|
||||||
|
"quotedblleft": "“",
|
||||||
|
"quotedblright": "”",
|
||||||
|
"semicolon": ";",
|
||||||
|
"slash": "/",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FontFace:
|
||||||
|
"""FontFace is a class holding glyphs
|
||||||
|
|
||||||
|
:param glyphs: dictionary of glyphs, defaults to ``{}``
|
||||||
|
:type glyphs: dict, optional
|
||||||
|
"""
|
||||||
|
def __init__(self, glyphs = {}):
|
||||||
|
self.glyphs = glyphs
|
||||||
|
|
||||||
|
|
||||||
|
class Font:
|
||||||
|
"""Font holds the faces and various metadata for a font
|
||||||
|
|
||||||
|
:param faces: dictionary of faces, defaults to ``Dict[str, FontFace]``
|
||||||
|
:type faces: Dict[str, FontFace]
|
||||||
|
"""
|
||||||
|
def __init__(self, faces = Dict[str, FontFace]):
|
||||||
|
self.faces = faces
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: better class structure?
|
||||||
|
# TODO: get fonts and faces directly
|
||||||
|
|
||||||
|
def add_glyph(font_name, face_name, glyph_id, glyph_object):
|
||||||
|
""" add_glyph adds a glyph to a FontFace
|
||||||
|
it creates the :class:`Font` and :class:`FontFace` if it does not exist yet
|
||||||
|
|
||||||
|
:param font_name: The Font you want to add the glyph to
|
||||||
|
:type font_name: str
|
||||||
|
:param face_name: The FontFace you want to add the glyph to
|
||||||
|
:type face_name: str
|
||||||
|
:param glyph_id: The glyph_id you want this glyph to be stored under
|
||||||
|
:type glyph_id: str
|
||||||
|
:param glyph_object: The object containing the glyph
|
||||||
|
:type glyph_object: `Object`
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not fonts.keys().__contains__(font_name):
|
||||||
|
fonts[font_name] = Font({})
|
||||||
|
print("is it has been added", fonts.keys())
|
||||||
|
if fonts[font_name].faces.get(face_name) == None:
|
||||||
|
fonts[font_name].faces[face_name] = FontFace({})
|
||||||
|
print("is it has been added faces", fonts[font_name].faces[face_name])
|
||||||
|
if fonts[font_name].faces[face_name].glyphs.get(glyph_id) == None:
|
||||||
|
fonts[font_name].faces[face_name].glyphs[glyph_id] = []
|
||||||
|
print("is it has been added glyph", fonts[font_name].faces[face_name].glyphs[glyph_id])
|
||||||
|
fonts[font_name].faces[face_name].glyphs.get(glyph_id).append(glyph_object)
|
||||||
|
|
||||||
|
|
||||||
|
def get_glyph(font_name, face_name, glyph_id):
|
||||||
|
""" add_glyph adds a glyph to a FontFace
|
||||||
|
it creates the :class:`Font` and :class:`FontFace` if it does not exist yet
|
||||||
|
|
||||||
|
:param font_name: The :class:`Font` you want to get the glyph from
|
||||||
|
:type font_name: str
|
||||||
|
:param face_name: The :class:`FontFace` you want to get the glyph from
|
||||||
|
:type face_name: str
|
||||||
|
:param glyph_id: The ``glyph_id`` from the glyph you want
|
||||||
|
:type glyph_id: str
|
||||||
|
...
|
||||||
|
:return: returns the glyph object, or ``None`` if it does not exist
|
||||||
|
:rtype: `Object`
|
||||||
|
"""
|
||||||
|
print(fonts)
|
||||||
|
if not fonts.keys().__contains__(font_name):
|
||||||
|
print(f"FONT3D::get_glyph: font name({font_name}) not found")
|
||||||
|
print(fonts.keys())
|
||||||
|
return None
|
||||||
|
|
||||||
|
if fonts[font_name].faces.get(face_name) == None:
|
||||||
|
print(f"FONT3D::get_glyph: font face({face_name}) not found")
|
||||||
|
print(fonts[font_name].faces.keys())
|
||||||
|
return None
|
||||||
|
|
||||||
|
if fonts[font_name].faces[face_name].glyphs.get(glyph_id) == None:
|
||||||
|
print(f"FONT3D::get_glyph: glyph id({glyph_id}) not found")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return fonts[font_name].faces[face_name].glyphs.get(glyph_id)[0]
|
||||||
|
|
||||||
|
# holds all fonts
|
||||||
|
fonts = {}
|
18
common/utils.py
Normal file
18
common/utils.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
import time
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
def get_timestamp():
|
||||||
|
return datetime.datetime \
|
||||||
|
.fromtimestamp(time.time()) \
|
||||||
|
.strftime('%Y.%m.%d-%H:%M:%S')
|
||||||
|
|
||||||
|
def mapRange(in_value, in_min, in_max, out_min, out_max, clamp=False):
|
||||||
|
output = out_min + ((out_max - out_min) / (in_max - in_min)) * (in_value - in_min)
|
||||||
|
if clamp:
|
||||||
|
if out_min < out_max:
|
||||||
|
return min(out_max, max(out_min, output))
|
||||||
|
else:
|
||||||
|
return max(out_max, min(out_min, output))
|
||||||
|
else:
|
||||||
|
return output
|
Loading…
Reference in a new issue