Created
October 29, 2015 23:47
-
-
Save pink-vertex/c9fd49e8348ea866a1b5 to your computer and use it in GitHub Desktop.
breakdown text curve into characters (experiment - tested on ubuntu 2.75a 64bit)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
import mathutils | |
import ctypes | |
c_int_p = ctypes.POINTER(ctypes.c_int) | |
c_float_p = ctypes.POINTER(ctypes.c_float) | |
class BezTriple(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ | |
("vec", (ctypes.c_float * 3) * 3), | |
("alfa", ctypes.c_float), | |
("weight", ctypes.c_float), | |
("radius", ctypes.c_float), | |
("ipo", ctypes.c_char), | |
("h1", ctypes.c_char), | |
("h2", ctypes.c_char), | |
("f1", ctypes.c_char), | |
("f2", ctypes.c_char), | |
("f3", ctypes.c_char), | |
("hide", ctypes.c_char), | |
("easing", ctypes.c_char), | |
("back", ctypes.c_float), | |
("amplitude", ctypes.c_float), | |
("period", ctypes.c_float), | |
("pad", ctypes.c_char * 4) | |
] | |
def get_coordinates(self): | |
v = self.vec | |
return (mathutils.Vector((v[0][0], v[0][1], v[0][2])), | |
mathutils.Vector((v[1][0], v[1][1], v[1][2])), | |
mathutils.Vector((v[2][0], v[2][1], v[2][2]))) | |
class BPoint(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ | |
("vec", ctypes.c_float * 4), | |
("alfa", ctypes.c_float), | |
("weight", ctypes.c_float), | |
("f1", ctypes.c_short), | |
("hide", ctypes.c_short), | |
("radius", ctypes.c_float), | |
("pad", ctypes.c_float), | |
] | |
def get_coordinates(self): | |
v = self.vec | |
return mathutils.Vector((v[0], v[1], v[2], v[3])) | |
BezTriple_p = ctypes.POINTER(BezTriple) | |
BPoint_p = ctypes.POINTER(BPoint) | |
class Nurb(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ # x64 | |
("prev", ctypes.c_void_p), # 8 | |
("next", ctypes.c_void_p), # 16 | |
("type", ctypes.c_short), # 18 | |
("mat_nr", ctypes.c_short), # 20 | |
("hide", ctypes.c_short), # 22 | |
("flag", ctypes.c_short), # 24 | |
("pntsu", ctypes.c_int), # 32 | |
("pntsv", ctypes.c_int), # 40 | |
("pad", ctypes.c_short * 2), # 44 | |
("resolu", ctypes.c_short), # 46 | |
("resolv", ctypes.c_short), # 48 | |
("orderu", ctypes.c_short), # 50 | |
("orderv", ctypes.c_short), # 52 | |
("flagu", ctypes.c_short), # 54 | |
("flagv", ctypes.c_short), # 56 | |
("knotsu", c_float_p), # 64 | |
("knotsv", c_float_p), # 72 | |
("bp", BPoint_p), # 80 | |
("bezt", BezTriple_p), # 88 | |
("tilt_interp", ctypes.c_short), # 92 | |
("radius_interp", ctypes.c_short), # 96 | |
("char_idx", ctypes.c_int), # 104 | |
] | |
def get_prev(self): | |
return (Nurb.from_address(self.prev) if self.prev else | |
None) | |
def get_next(self): | |
return (Nurb.from_address(self.next) if self.next else | |
None) | |
class ID(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ | |
("next", ctypes.c_void_p), | |
("prev", ctypes.c_void_p), | |
("newid", ctypes.c_void_p), | |
("lib", ctypes.c_void_p), | |
("name", ctypes.c_char * 66), | |
("flag", ctypes.c_short), | |
("us", ctypes.c_int), | |
("icon_id", ctypes.c_int), | |
("pad2", ctypes.c_int), | |
("properties", ctypes.c_void_p) | |
] | |
class Entry(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ | |
("next", ctypes.c_void_p), | |
("key", ctypes.c_void_p) | |
] | |
def get_next(self): | |
return (Entry.from_address(self.next) if self.next else | |
None) | |
def as_ghash_entry(self): | |
#ctypes.cast does not work here :/ | |
return GHashEntry.from_address(ctypes.addressof(self)) | |
class GHashEntry(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ | |
("e", Entry), | |
("val", ctypes.c_void_p) | |
] | |
Hash_fp = ctypes.CFUNCTYPE(ctypes.c_uint, ctypes.c_void_p) | |
Cmp_fp = ctypes.CFUNCTYPE(ctypes.c_uint, ctypes.c_void_p, ctypes.c_void_p) | |
Entry_pp = ctypes.POINTER(ctypes.POINTER(Entry)) | |
class GHash(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ | |
("hashfp", Hash_fp), | |
("cmpfp", Cmp_fp), | |
("buckets", Entry_pp), | |
("entrypool", ctypes.c_void_p), | |
("nbuckets", ctypes.c_uint), | |
("limit_grow", ctypes.c_uint), | |
("limit_shrink", ctypes.c_uint), | |
("cursize", ctypes.c_uint), | |
("size_min", ctypes.c_uint), | |
("nentries", ctypes.c_uint), | |
("flag", ctypes.c_uint) | |
] | |
GHash_p = ctypes.POINTER(GHash) | |
class VFontData(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ | |
("characters", GHash_p), | |
("name", ctypes.c_char * 128), | |
("scale", ctypes.c_float) | |
] | |
VFontData_p = ctypes.POINTER(VFontData) | |
class VFont(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ | |
("id", ID), | |
("name", ctypes.c_char * 1024), | |
("data", VFontData_p), | |
("packedfile", ctypes.c_void_p), | |
("temp_pf", ctypes.c_void_p) | |
] | |
class VChar(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ | |
("first", ctypes.c_void_p), | |
("last", ctypes.c_void_p), | |
("index", ctypes.c_uint), | |
("width", ctypes.c_float), | |
] | |
if __name__ == "__main__": | |
scene = bpy.context.scene | |
text_curve = bpy.data.curves['Text'] | |
vfont = text_curve.font | |
pointer = vfont.as_pointer() | |
vfont_struct = VFont.from_address(pointer) | |
print("\nName: %s" % vfont_struct.name) | |
print( "Name: %s" % vfont_struct.id.name) | |
print( "Name: %s" % vfont_struct.data.contents.name) | |
body = text_curve.body | |
char_indices = [ord(char) for char in body] | |
entries = [None] * len(body) | |
gh = vfont_struct.data.contents.characters.contents | |
for index, char_idx in enumerate(char_indices): | |
hash = gh.hashfp(char_idx) | |
bucket_index = hash % gh.nbuckets | |
e = gh.buckets[bucket_index].contents | |
while(e): | |
if e.key == char_idx: | |
entries[index] = e.as_ghash_entry() | |
break | |
e = e.get_next() | |
def create_bezier_curve(scene, data, name): | |
cu = bpy.data.curves.get(name) | |
if not cu: | |
cu = bpy.data.curves.new(name, "CURVE") | |
else: | |
cu.splines.clear() | |
for nu in data: | |
# will be created with one bezier point | |
spline = cu.splines.new("BEZIER") | |
spline.bezier_points.add(nu.pntsu - 1) | |
spline.use_cyclic_u = True | |
# readonly | |
Nurb.from_address(spline.as_pointer()).char_idx = nu.char_idx | |
for i, point in enumerate(spline.bezier_points): | |
(point.handle_left, | |
point.co, | |
point.handle_right) = nu.bezt[i].get_coordinates() | |
obj = bpy.data.objects.get(name) | |
if not obj: | |
obj = bpy.data.objects.new(name, cu) | |
scene.objects.link(obj) | |
else: | |
obj.data = cu | |
return obj | |
offset = 0.0 | |
splines = [None] * 8 | |
for entry, char_idx in zip(entries, char_indices): | |
vc = VChar.from_address(entry.val) | |
print("Ctypes: %d, python: %d" % (vc.index, char_idx)) | |
nu = Nurb.from_address(vc.first) if vc.first else None | |
count = 0 | |
while(nu): | |
splines[count] = nu | |
count += 1 | |
if(ctypes.addressof(nu) == vc.last): | |
break | |
else: | |
nu = nu.get_prev() | |
cu_obj = create_bezier_curve(scene, splines[:count], "Char%04d" % vc.index) | |
cu_obj.location.x = offset | |
cu_obj.location.y = 1.0 | |
offset += vc.width | |
class ListBase(ctypes.Structure): | |
_pack_ = 8 | |
_fields_ = [ | |
("first", ctypes.c_void_p), | |
("last", ctypes.c_void_p) | |
] | |
bl = ctypes.cdll.LoadLibrary('') | |
func_convert = bl.BKE_vfont_to_curve_ex | |
func_free = bl.BKE_nurbList_free | |
NULL = ctypes.c_void_p() | |
bmain = ctypes.c_void_p(bpy.data.as_pointer()) | |
ob = ctypes.c_void_p(bpy.data.objects['Text'].as_pointer()) | |
mode = 0 | |
r_nubase = ctypes.pointer(ListBase(NULL, NULL)) | |
r_text = NULL | |
r_text_len = NULL | |
r_text_free = NULL | |
r_chartransdata = NULL | |
result = func_convert( | |
bmain, ob, mode, r_nubase, | |
r_text, r_text_len, r_text_free, | |
r_chartransdata) | |
from collections import deque | |
splines = deque() | |
lb = r_nubase.contents | |
nu = Nurb.from_address(lb.first) if lb.first else None | |
while(nu): | |
splines.append(nu) | |
if ctypes.addressof(nu) == lb.last: | |
break | |
else: | |
nu = nu.get_prev() | |
cu_obj = create_bezier_curve(scene, splines, "Result") | |
cu_obj.location.y = 2.0 | |
print("Success: %s" % result) | |
print(*(spline.character_index for spline in cu_obj.data.splines)) | |
func_free(r_nubase) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment