Compare commits
32 commits
Author | SHA1 | Date | |
---|---|---|---|
a5602a6095 | |||
cd99362bb1 | |||
f02f8fc2f0 | |||
e95266afc9 | |||
58e0df3427 | |||
7de8fcc5d1 | |||
14d1b7a160 | |||
59edb2e786 | |||
bb0a5a4a2c | |||
6160b99c93 | |||
d61607c75d | |||
8470425d20 | |||
01fcb60e31 | |||
7a43cfaf2f | |||
2dcd4e7a2c | |||
9423659153 | |||
19f4bf586f | |||
04229fbc31 | |||
963d89daf9 | |||
3ef2ae934d | |||
8965ab11eb | |||
513497d492 | |||
335ab1face | |||
777644e509 | |||
e14251523b | |||
8f3d58aad0 | |||
2ace31a246 | |||
88cfaf3be7 | |||
10e57dd46a | |||
c27cf41368 | |||
7a034efd1c | |||
3ea2f0e304 |
10 changed files with 2086 additions and 774 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
||||||
# python
|
# python
|
||||||
__pycache__
|
__pycache__
|
||||||
venv
|
venv
|
||||||
|
venv*
|
||||||
|
|
||||||
# vim
|
# vim
|
||||||
*.swo
|
*.swo
|
||||||
|
|
|
@ -5,10 +5,8 @@
|
||||||
/ ___ \| |_) | |___ ___) | |_| |
|
/ ___ \| |_) | |___ ___) | |_| |
|
||||||
/_/ \_\____/ \____|____/|____/
|
/_/ \_\____/ \____|____/|____/
|
||||||
```
|
```
|
||||||
v0.0.8
|
v0.0.12
|
||||||
|
|
||||||
Convenience tool to work with 3D typography in Blender and Cinema4D.
|
Convenience addon to work with 3D typography in Blender and Cinema4D.
|
||||||
|
|
||||||
Install as you would normally install an addon.
|
|
||||||
|
|
||||||
Instructions for development in [CONTRIBUTING,md](./CONTRIBUTING.md).
|
Instructions for development in [CONTRIBUTING,md](./CONTRIBUTING.md).
|
||||||
|
|
730
__init__.py
730
__init__.py
File diff suppressed because it is too large
Load diff
143
common/Font.py
143
common/Font.py
|
@ -1,5 +1,5 @@
|
||||||
from typing import Dict
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Dict, NamedTuple
|
||||||
|
|
||||||
# convenience dictionary for translating names to glyph ids
|
# convenience dictionary for translating names to glyph ids
|
||||||
# note: overwritten/extended by the content of "glypNamesToUnicode.txt"
|
# note: overwritten/extended by the content of "glypNamesToUnicode.txt"
|
||||||
|
@ -177,6 +177,34 @@ def register_font(font_name, face_name, glyphs_in_fontfile, filepath):
|
||||||
fonts[font_name].faces[face_name].filepaths.append(filepath)
|
fonts[font_name].faces[face_name].filepaths.append(filepath)
|
||||||
|
|
||||||
|
|
||||||
|
def get_font(font_name):
|
||||||
|
if not fonts.keys().__contains__(font_name):
|
||||||
|
print(f"ABC3D::get_font: font name({font_name}) not found")
|
||||||
|
print(fonts.keys())
|
||||||
|
return None
|
||||||
|
return fonts[font_name]
|
||||||
|
|
||||||
|
|
||||||
|
def get_font_face(font_name, face_name):
|
||||||
|
font = get_font(font_name)
|
||||||
|
if font is None:
|
||||||
|
return None
|
||||||
|
if not font.faces.keys().__contains__(face_name):
|
||||||
|
print(
|
||||||
|
f"ABC3D::get_font_face (font: {font_name}): face name({face_name}) not found"
|
||||||
|
)
|
||||||
|
print(font.faces.keys())
|
||||||
|
return None
|
||||||
|
return font.faces[face_name]
|
||||||
|
|
||||||
|
|
||||||
|
def get_font_face_filepaths(font_name, face_name):
|
||||||
|
face = get_font_face(font_name, face_name)
|
||||||
|
if not face:
|
||||||
|
return None
|
||||||
|
return face.filepaths
|
||||||
|
|
||||||
|
|
||||||
def add_glyph(font_name, face_name, glyph_id, glyph_object):
|
def add_glyph(font_name, face_name, glyph_id, glyph_object):
|
||||||
"""add_glyph adds a glyph to a FontFace
|
"""add_glyph adds a glyph to a FontFace
|
||||||
it creates the :class:`Font` and :class:`FontFace` if it does not exist yet
|
it creates the :class:`Font` and :class:`FontFace` if it does not exist yet
|
||||||
|
@ -203,7 +231,48 @@ def add_glyph(font_name, face_name, glyph_id, glyph_object):
|
||||||
fonts[font_name].faces[face_name].loaded_glyphs.append(glyph_id)
|
fonts[font_name].faces[face_name].loaded_glyphs.append(glyph_id)
|
||||||
|
|
||||||
|
|
||||||
def get_glyph(font_name, face_name, glyph_id, alternate=0):
|
def get_glyphs(font_name, face_name, glyph_id):
|
||||||
|
"""get_glyphs returns an array of glyphs of a FontFace
|
||||||
|
|
||||||
|
: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 a list of the glyph objects, or an empty list if none exists
|
||||||
|
:rtype: `List`
|
||||||
|
"""
|
||||||
|
|
||||||
|
face = get_font_face(font_name, face_name)
|
||||||
|
if face is None:
|
||||||
|
print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) not found")
|
||||||
|
try:
|
||||||
|
print(fonts[font_name].faces.keys())
|
||||||
|
except:
|
||||||
|
print(fonts.keys())
|
||||||
|
return []
|
||||||
|
|
||||||
|
glyphs_for_id = face.glyphs.get(glyph_id)
|
||||||
|
if glyphs_for_id is None:
|
||||||
|
print(
|
||||||
|
f"ABC3D::get_glyph: font({font_name}) face({face_name}) glyph({glyph_id}) 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 []
|
||||||
|
|
||||||
|
return glyphs_for_id
|
||||||
|
|
||||||
|
|
||||||
|
def get_glyph(
|
||||||
|
font_name: str,
|
||||||
|
face_name: str,
|
||||||
|
glyph_id: str,
|
||||||
|
alternate: int = 0,
|
||||||
|
alternate_tolerant: bool = True,
|
||||||
|
):
|
||||||
"""add_glyph adds a glyph to a FontFace
|
"""add_glyph adds a glyph to a FontFace
|
||||||
it creates the :class:`Font` and :class:`FontFace` if it does not exist yet
|
it creates the :class:`Font` and :class:`FontFace` if it does not exist yet
|
||||||
|
|
||||||
|
@ -213,30 +282,53 @@ def get_glyph(font_name, face_name, glyph_id, alternate=0):
|
||||||
:type face_name: str
|
:type face_name: str
|
||||||
:param glyph_id: The ``glyph_id`` from the glyph you want
|
:param glyph_id: The ``glyph_id`` from the glyph you want
|
||||||
:type glyph_id: str
|
:type glyph_id: str
|
||||||
|
:param alternate: The ``alternate`` from the glyph you want
|
||||||
|
:type alternate: int
|
||||||
|
:param alternate_tolerant: Fetch an existing alternate if requested is out of bounds
|
||||||
|
:type glyph_id: bool
|
||||||
...
|
...
|
||||||
:return: returns the glyph object, or ``None`` if it does not exist
|
:return: returns the glyph object, or ``None`` if it does not exist
|
||||||
:rtype: `Object`
|
:rtype: `Object`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not fonts.keys().__contains__(font_name):
|
glyphs = get_glyphs(font_name, face_name, glyph_id)
|
||||||
# print(f"ABC3D::get_glyph: font name({font_name}) not found")
|
|
||||||
# print(fonts.keys())
|
if len(glyphs) == 0:
|
||||||
|
print(
|
||||||
|
f"ABC3D::get_glyph: font({font_name}) face({face_name}) glyph({glyph_id})[{alternate}] not found"
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
face = fonts[font_name].faces.get(face_name)
|
if len(glyphs) <= alternate:
|
||||||
|
if alternate_tolerant:
|
||||||
|
alternate = 0
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"ABC3D::get_glyph: font({font_name}) face({face_name}) glyph({glyph_id})[{alternate}] not found"
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
return glyphs[alternate]
|
||||||
|
|
||||||
|
|
||||||
|
def unloaded_glyph(font_name, face_name, glyph_id):
|
||||||
|
face = get_font_face(font_name, face_name)
|
||||||
if face is None:
|
if face is None:
|
||||||
# print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) not found")
|
print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) not found")
|
||||||
# print(fonts[font_name].faces.keys())
|
return
|
||||||
return None
|
while True:
|
||||||
|
try:
|
||||||
|
fonts[font_name].faces[face_name].loaded_glyphs.remove(glyph_id)
|
||||||
|
del fonts[font_name].faces[face_name].glyphs[glyph_id]
|
||||||
|
except ValueError:
|
||||||
|
break
|
||||||
|
|
||||||
glyphs_for_id = face.glyphs.get(glyph_id)
|
|
||||||
if glyphs_for_id is None or len(glyphs_for_id) <= alternate:
|
|
||||||
# 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
|
|
||||||
|
|
||||||
return fonts[font_name].faces[face_name].glyphs.get(glyph_id)[alternate]
|
class GlyphsAvailability(NamedTuple):
|
||||||
|
loaded: str
|
||||||
|
missing: str
|
||||||
|
unloaded: str
|
||||||
|
filepaths: list[str]
|
||||||
|
|
||||||
|
|
||||||
def test_glyphs_availability(font_name, face_name, text):
|
def test_glyphs_availability(font_name, face_name, text):
|
||||||
|
@ -245,24 +337,24 @@ def test_glyphs_availability(font_name, face_name, text):
|
||||||
not fonts.keys().__contains__(font_name)
|
not fonts.keys().__contains__(font_name)
|
||||||
or fonts[font_name].faces.get(face_name) is None
|
or fonts[font_name].faces.get(face_name) is None
|
||||||
):
|
):
|
||||||
return "", "", text # <loaded>, <missing>, <maybe>
|
return GlyphsAvailability("", "", "", [])
|
||||||
|
|
||||||
loaded = []
|
loaded = []
|
||||||
missing = []
|
missing = []
|
||||||
maybe = []
|
unloaded = []
|
||||||
for c in text:
|
for c in text:
|
||||||
if c in fonts[font_name].faces[face_name].loaded_glyphs:
|
if c in fonts[font_name].faces[face_name].loaded_glyphs:
|
||||||
loaded.append(c)
|
loaded.append(c)
|
||||||
elif c in fonts[font_name].faces[face_name].glyphs_in_fontfile:
|
elif c in fonts[font_name].faces[face_name].glyphs_in_fontfile:
|
||||||
maybe.append(c)
|
unloaded.append(c)
|
||||||
else:
|
else:
|
||||||
if c not in fonts[font_name].faces[face_name].missing_glyphs:
|
if c not in fonts[font_name].faces[face_name].missing_glyphs:
|
||||||
fonts[font_name].faces[face_name].missing_glyphs.append(c)
|
fonts[font_name].faces[face_name].missing_glyphs.append(c)
|
||||||
missing.append(c)
|
missing.append(c)
|
||||||
return (
|
return GlyphsAvailability(
|
||||||
"".join(loaded),
|
"".join(loaded),
|
||||||
"".join(missing),
|
"".join(missing),
|
||||||
"".join(maybe),
|
"".join(unloaded),
|
||||||
fonts[font_name].faces[face_name].filepaths,
|
fonts[font_name].faces[face_name].filepaths,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -288,15 +380,10 @@ def test_availability(font_name, face_name, text):
|
||||||
return MISSING_FONT
|
return MISSING_FONT
|
||||||
if fonts[font_name].faces.get(face_name) is None:
|
if fonts[font_name].faces.get(face_name) is None:
|
||||||
return MISSING_FACE
|
return MISSING_FACE
|
||||||
loaded, missing, maybe, filepaths = test_glyphs_availability(
|
availability: GlyphsAvailability = test_glyphs_availability(
|
||||||
font_name, face_name, text
|
font_name, face_name, text
|
||||||
)
|
)
|
||||||
return {
|
return availability
|
||||||
"loaded": loaded,
|
|
||||||
"missing": missing,
|
|
||||||
"maybe": maybe,
|
|
||||||
"filepaths": filepaths,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# holds all fonts
|
# holds all fonts
|
||||||
|
|
|
@ -4,20 +4,20 @@ space 0020 0.25
|
||||||
nbspace 00A0 0.25
|
nbspace 00A0 0.25
|
||||||
# ethi:wordspace 1361 # NOTE: has shape
|
# ethi:wordspace 1361 # NOTE: has shape
|
||||||
enquad 2000 0.5
|
enquad 2000 0.5
|
||||||
emquad 2001 1
|
emquad 2001 1.0
|
||||||
enspace 2002 0.5
|
enspace 2002 0.5
|
||||||
emspace 2003 1
|
emspace 2003 1.0
|
||||||
threeperemspace 2004 3
|
threeperemspace 2004 3.0
|
||||||
fourperemspace 2005 4
|
fourperemspace 2005 4.0
|
||||||
sixperemspace 2006 6
|
sixperemspace 2006 6.0
|
||||||
figurespace 2007 1
|
figurespace 2007 1.0
|
||||||
punctuationspace 2008 1
|
punctuationspace 2008 1.0
|
||||||
thinspace 2009 0.1
|
thinspace 2009 0.1
|
||||||
hairspace 200A 0.05
|
hairspace 200A 0.05
|
||||||
zerowidthspace 200B 0
|
zerowidthspace 200B 0.0
|
||||||
narrownobreakspace 202F 0.1
|
narrownobreakspace 202F 0.1
|
||||||
mediummathematicalspace 205F 1
|
mediummathematicalspace 205F 1.0
|
||||||
cntr:space 2420 0.25
|
cntr:space 2420 0.25
|
||||||
ideographicspace 3000 1
|
ideographicspace 3000 1.0
|
||||||
# ideographichalffillspace 303F # NOTE: has shape
|
# ideographichalffillspace 303F # NOTE: has shape
|
||||||
zerowidthnobreakspace FEFF 0
|
zerowidthnobreakspace FEFF 0.0
|
||||||
|
|
|
@ -8,11 +8,11 @@ def get_version_minor():
|
||||||
|
|
||||||
|
|
||||||
def get_version_patch():
|
def get_version_patch():
|
||||||
return 8
|
return 12
|
||||||
|
|
||||||
|
|
||||||
def get_version_string():
|
def get_version_string():
|
||||||
return f"{get_version_major()}.{get_version_minor()}.{get_version_patch}"
|
return f"{get_version_major()}.{get_version_minor()}.{get_version_patch()}"
|
||||||
|
|
||||||
|
|
||||||
def prefix():
|
def prefix():
|
||||||
|
@ -23,7 +23,6 @@ import datetime
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_timestamp():
|
def get_timestamp():
|
||||||
return datetime.datetime.fromtimestamp(time.time()).strftime("%Y.%m.%d-%H:%M:%S")
|
return datetime.datetime.fromtimestamp(time.time()).strftime("%Y.%m.%d-%H:%M:%S")
|
||||||
|
|
||||||
|
@ -82,6 +81,10 @@ def open_file_browser(directory):
|
||||||
# xdg-open *should* be supported by recent Gnome, KDE, Xfce
|
# xdg-open *should* be supported by recent Gnome, KDE, Xfce
|
||||||
|
|
||||||
|
|
||||||
|
def LINE():
|
||||||
|
return sys._getframe(1).f_lineno
|
||||||
|
|
||||||
|
|
||||||
def printerr(*args, **kwargs):
|
def printerr(*args, **kwargs):
|
||||||
print(*args, file=sys.stderr, **kwargs)
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
@ -90,6 +93,34 @@ def removeNonAlphabetic(s):
|
||||||
return "".join([i for i in s if i.isalpha()])
|
return "".join([i for i in s if i.isalpha()])
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
|
||||||
|
def can_create_path(path_str: str):
|
||||||
|
path = pathlib.Path(path_str).absolute().resolve()
|
||||||
|
|
||||||
|
tries = 0
|
||||||
|
maximum_tries = 1000
|
||||||
|
while True:
|
||||||
|
if path.exists():
|
||||||
|
if os.access(path, os.W_OK):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
elif path == path.parent:
|
||||||
|
# should never be reached, because root exists
|
||||||
|
# but if it doesn't.. well then we can't
|
||||||
|
return False
|
||||||
|
|
||||||
|
path = path.parent
|
||||||
|
tries += 1
|
||||||
|
if tries > maximum_tries:
|
||||||
|
# always, always break out of while loops eventually
|
||||||
|
# IF you don't want to be here forever
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
# # Evaluate a bezier curve for the parameter 0<=t<=1 along its length
|
# # Evaluate a bezier curve for the parameter 0<=t<=1 along its length
|
||||||
# def evaluateBezierPoint(p1, h1, h2, p2, t):
|
# 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
|
# return ((1 - t)**3) * p1 + (3 * t * (1 - t)**2) * h1 + (3 * (t**2) * (1 - t)) * h2 + (t**3) * p2
|
||||||
|
|
|
@ -1,33 +1,39 @@
|
||||||
astroid==3.3.5
|
asttokens==3.0.0
|
||||||
attrs==24.2.0
|
attrs==25.3.0
|
||||||
black==24.10.0
|
bpy==4.4.0
|
||||||
bpy==4.2.0
|
cattrs==24.1.3
|
||||||
cattrs==24.1.2
|
certifi==2025.4.26
|
||||||
certifi==2024.8.30
|
charset-normalizer==3.4.2
|
||||||
charset-normalizer==3.4.0
|
Cython==3.1.1
|
||||||
click==8.1.7
|
decorator==5.2.1
|
||||||
Cython==3.0.11
|
docstring-to-markdown==0.17
|
||||||
dill==0.3.9
|
executing==2.2.0
|
||||||
docstring-to-markdown==0.15
|
|
||||||
flake8==7.1.1
|
|
||||||
idna==3.10
|
idna==3.10
|
||||||
isort==5.13.2
|
importlib_metadata==8.7.0
|
||||||
jedi==0.19.1
|
ipython==9.2.0
|
||||||
jedi-language-server==0.41.4
|
ipython_pygments_lexers==1.1.1
|
||||||
|
jedi==0.19.2
|
||||||
|
jedi-language-server==0.45.1
|
||||||
lsprotocol==2023.0.1
|
lsprotocol==2023.0.1
|
||||||
mathutils==3.3.0
|
mathutils==3.3.0
|
||||||
mccabe==0.7.0
|
matplotlib-inline==0.1.7
|
||||||
mypy-extensions==1.0.0
|
numpy==1.26.4
|
||||||
numpy==2.1.3
|
|
||||||
packaging==24.1
|
|
||||||
parso==0.8.4
|
parso==0.8.4
|
||||||
pathspec==0.12.1
|
pexpect==4.9.0
|
||||||
platformdirs==4.3.6
|
pluggy==1.6.0
|
||||||
pycodestyle==2.12.1
|
prompt_toolkit==3.0.51
|
||||||
pyflakes==3.2.0
|
ptyprocess==0.7.0
|
||||||
|
pure_eval==0.2.3
|
||||||
pygls==1.3.1
|
pygls==1.3.1
|
||||||
pylint==3.3.1
|
Pygments==2.19.1
|
||||||
|
python-jsonrpc-server==0.4.0
|
||||||
|
python-lsp-jsonrpc==1.1.2
|
||||||
requests==2.32.3
|
requests==2.32.3
|
||||||
tomlkit==0.13.2
|
stack-data==0.6.3
|
||||||
urllib3==2.2.3
|
traitlets==5.14.3
|
||||||
|
typing_extensions==4.13.2
|
||||||
|
ujson==5.10.0
|
||||||
|
urllib3==2.4.0
|
||||||
|
wcwidth==0.2.13
|
||||||
|
zipp==3.22.0
|
||||||
zstandard==0.23.0
|
zstandard==0.23.0
|
||||||
|
|
25
testing_scripts/bezier_distance.py
Normal file
25
testing_scripts/bezier_distance.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import bpy
|
||||||
|
from mathutils import *
|
||||||
|
from math import *
|
||||||
|
import abc3d.butils
|
||||||
|
|
||||||
|
v = 0
|
||||||
|
goal = 5.0
|
||||||
|
step = 0.1
|
||||||
|
speed = 1.0
|
||||||
|
|
||||||
|
C = bpy.context
|
||||||
|
obj = C.scene.objects['Cube']
|
||||||
|
curve = C.scene.objects['BézierCurve']
|
||||||
|
|
||||||
|
m = curve.matrix
|
||||||
|
|
||||||
|
def fun(distance):
|
||||||
|
obj.location = m @ abc3d.butils.calc_point_on_bezier_curve(curve,
|
||||||
|
distance,
|
||||||
|
output_tangent=True)
|
||||||
|
print(f"executed {distance}")
|
||||||
|
|
||||||
|
while v < goal:
|
||||||
|
bpy.app.timers.register(lambda: fun(v), first_interval=(v * speed))
|
||||||
|
v += step
|
115
testing_scripts/unload_glyphs.py
Normal file
115
testing_scripts/unload_glyphs.py
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
import abc3d
|
||||||
|
from abc3d import butils
|
||||||
|
from abc3d.common import Font
|
||||||
|
|
||||||
|
|
||||||
|
def get_text_properties_by_mom(mom):
|
||||||
|
scene = bpy.context.scene
|
||||||
|
abc3d_data = scene.abc3d_data
|
||||||
|
|
||||||
|
for text_properties in abc3d_data.available_texts:
|
||||||
|
if mom == text_properties.text_object:
|
||||||
|
return text_properties
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def isolate_objects(objects):
|
||||||
|
for area in bpy.context.window.screen.areas:
|
||||||
|
if area.type == "VIEW_3D":
|
||||||
|
with bpy.context.temp_override(
|
||||||
|
selected_objects=list(objects),
|
||||||
|
area=area,
|
||||||
|
refgion=[region for region in area.regions if region.type == "WINDOW"][
|
||||||
|
0
|
||||||
|
],
|
||||||
|
screen=bpy.context.window.screen,
|
||||||
|
):
|
||||||
|
# bpy.ops.view3d.view_selected()
|
||||||
|
bpy.ops.view3d.localview(frame_selected=True)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# create a curve
|
||||||
|
bpy.ops.curve.primitive_bezier_curve_add(
|
||||||
|
radius=1,
|
||||||
|
enter_editmode=False,
|
||||||
|
align="WORLD",
|
||||||
|
location=(0, 0, 0),
|
||||||
|
scale=(1, 1, 1),
|
||||||
|
)
|
||||||
|
# new curve is active object
|
||||||
|
mom = bpy.context.active_object
|
||||||
|
|
||||||
|
# make sure
|
||||||
|
print(f"MOM: {mom.name}")
|
||||||
|
|
||||||
|
fonts = Font.get_loaded_fonts_and_faces()
|
||||||
|
if len(fonts) == 0:
|
||||||
|
print("no fonts! what?")
|
||||||
|
return
|
||||||
|
|
||||||
|
font_name = fonts[0][0]
|
||||||
|
face_name = fonts[0][1]
|
||||||
|
font = f"{font_name} {face_name}"
|
||||||
|
|
||||||
|
isolate_objects([mom])
|
||||||
|
|
||||||
|
bpy.ops.abc3d.placetext(
|
||||||
|
font_name=font_name,
|
||||||
|
face_name=face_name,
|
||||||
|
font=font,
|
||||||
|
text="SOMETHING SOMETHING BROKEN ARMS",
|
||||||
|
letter_spacing=0,
|
||||||
|
font_size=1,
|
||||||
|
offset=0,
|
||||||
|
translation=(0, 0, 0),
|
||||||
|
orientation=(1.5708, 0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
def change_text(font_name="", face_name="", text=""):
|
||||||
|
print(f"change_text to '{text}'")
|
||||||
|
text_properties = get_text_properties_by_mom(mom)
|
||||||
|
if font_name != "":
|
||||||
|
text_properties["font_name"] = font_name
|
||||||
|
if face_name != "":
|
||||||
|
text_properties["face_name"] = face_name
|
||||||
|
if text != "":
|
||||||
|
text_properties.text = text
|
||||||
|
else:
|
||||||
|
text_properties.text = text_properties.text
|
||||||
|
return None
|
||||||
|
|
||||||
|
def unload(glyph_id):
|
||||||
|
print(f"unload glyph '{glyph_id}'")
|
||||||
|
butils.unload_unused_glyph(font_name, face_name, glyph_id)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def unload_all():
|
||||||
|
print(f"unload glyph all unused glyphs")
|
||||||
|
butils.unload_unused_glyphs()
|
||||||
|
return None
|
||||||
|
|
||||||
|
bpy.app.timers.register(lambda: change_text(text="SOMETHING"), first_interval=0)
|
||||||
|
bpy.app.timers.register(lambda: change_text(text="LOLSS"), first_interval=2)
|
||||||
|
bpy.app.timers.register(lambda: change_text(text="LOLAA"), first_interval=3)
|
||||||
|
bpy.app.timers.register(lambda: change_text(text="WHAT"), first_interval=4)
|
||||||
|
bpy.app.timers.register(lambda: change_text(text="LOL"), first_interval=5)
|
||||||
|
|
||||||
|
bpy.app.timers.register(lambda: unload("A"), first_interval=10)
|
||||||
|
bpy.app.timers.register(lambda: unload_all(), first_interval=12)
|
||||||
|
|
||||||
|
bpy.app.timers.register(lambda: change_text(text="LOLM"), first_interval=16)
|
||||||
|
bpy.app.timers.register(lambda: change_text(text="ZHE END"), first_interval=20)
|
||||||
|
|
||||||
|
bpy.app.timers.register(
|
||||||
|
lambda: change_text(font_name="NM_Origin", face_name="Tender"),
|
||||||
|
first_interval=30,
|
||||||
|
)
|
||||||
|
|
||||||
|
bpy.app.timers.register(lambda: unload_all(), first_interval=42)
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
Loading…
Add table
Add a link
Reference in a new issue