Following on to the previous post where I dumped blender scenes as Lisp, I've also written a modified version which is more usual for mainstream use that dumps the entire active object as an enormous Lua literal. I think this would be more useful for mainstream use as the Lua could then be compiled to binary and loaded into a tool, which could pick out and use the useful bits on a per-project basis. My next project is to investigate if such a thing is also possible with FBX & Python - again for more mainstream use.
Once more, here is the source Luke - use it :-)
This file contains 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
bl_info = { | |
"name": "Export Scene as Lua (.lua)", | |
"author": "John Connors (ZabaQ)", | |
"version": (0, 7), | |
"blender": (2, 5, 4), | |
"api": 33047, | |
"location": "File > Export", | |
"description": "Blender Scene To Lua (.lua)", | |
"warning": "", | |
"category": "Import-Export"} | |
import bpy | |
import mathutils | |
import types | |
# ExportHelper is a helper class, defines filename and | |
# invoke() function which calls the file selector. | |
from bpy_extras.io_utils import ExportHelper | |
from bpy.props import StringProperty, BoolProperty, EnumProperty | |
# transform python property to lua id | |
def luaify(s): | |
if ((s == None) or (s[-1:]==']')): | |
return None | |
result = s.split('.')[-1:] | |
result = result[0].lower() | |
return result | |
def escape_lua_string(s): | |
broken = s.split("\\") | |
return "\\\\".join(broken) | |
def introspect_obj(o, txt, indent = 4): | |
global annotate_file | |
global outfile | |
type_o = type(o) | |
# it has a key associated with it | |
if (txt != None): | |
luaname = luaify(txt) | |
if (luaname != None): | |
if annotate_file: | |
print("", file=outfile) | |
print(" " * indent, end='', file=outfile) | |
print ( "--[[ " + txt + " " + str(type_o) + "]] ", end = '', file=outfile) | |
print("", file=outfile) | |
print(" " * indent, end='', file=outfile) | |
print ( luaname + " = ", end = '', file=outfile ) | |
# not interested in functions | |
if (type_o in [ types.CodeType, types.BuiltinFunctionType, types.BuiltinMethodType, types.FunctionType, types.LambdaType, types.MethodType ]): | |
print ("nil ", end = '', file=outfile) | |
return | |
if (str(type_o) == "<class 'bpy_func'>"): # must be a better way to do this | |
print ("nil ", end = '', file=outfile) | |
return | |
# now for the value | |
# boolean | |
if (type_o == bool): | |
if (o == False): | |
print("false ", end = '', file=outfile) | |
else: | |
print("true ", end = '', file=outfile) | |
return | |
# None | |
if (o == None): | |
print ("nil ", end = '', file=outfile) | |
return | |
# Numeric | |
if (type_o in [ int, float ]): | |
print(o, " ", end='', file=outfile) | |
return | |
# string | |
if (issubclass(type_o, str)): | |
print ("\"" + escape_lua_string(o) + "\" ", file=outfile, end='') | |
return | |
if txt == None: | |
return | |
# we do this explicitly to avoid the madness of swizzling (100s of members per vector!) | |
if (type_o == mathutils.Vector): | |
items = [ 'x', 'y', 'z', 'w' ] | |
print( " { ", end = '' , file=outfile) | |
for item in items: | |
newtxt = txt + '.' + item | |
val = getattr(o, item, None) | |
if (val != None): | |
print(" ", end='', file=outfile) | |
introspect_obj( val, newtxt, indent + 4 ) | |
print(" , ", end='', file=outfile) | |
print( " } --[[ vec ]] ", end = '' , file=outfile) | |
return | |
# object members | |
try: __members__ = dir(o) | |
except: __members__ = [] | |
# all kinds of stuff turns up in dir(), so filter it out | |
if (__members__ != []): | |
fields = [] | |
for item in __members__: | |
# internal data | |
if item.startswith("__"): | |
continue | |
# Blenders own type system gets in the way | |
if item in [ 'rna_type', 'bl_rna', 'owner' ]: | |
continue | |
if item in txt: | |
continue | |
# we want data, not funcitions | |
type_i = type(getattr(o, item, None)) | |
if (type_i in [ types.CodeType, types.BuiltinFunctionType, types.BuiltinMethodType, types.FunctionType, types.LambdaType ]): | |
continue | |
if (str(type_i) == "<class 'bpy_func'>"): # must be a better way to do this | |
continue | |
fields += [ item ] | |
# if there's anything left, print it | |
if (len(fields) != 0): | |
print("", end = '', file=outfile) | |
print(" " * indent, end='', file=outfile) | |
print("{", end = '' , file=outfile) | |
itemindex = 0 | |
fi = len(fields) | |
for item in fields: | |
newtxt = txt + '.' + item | |
# print(" -- %s " % newtxt, end='', file=outfile) | |
itemindex = itemindex + 1 | |
introspect_obj( getattr(o, item, None), newtxt, indent + 4) | |
fi = fi - 1 | |
if (fi > 0): | |
print(" , ", end='', file=outfile) | |
print( " } --[[ fields ]] ", end='', file=outfile) | |
return | |
# now, try dict types | |
try: keys = o.keys() | |
except: keys = None | |
if keys: | |
print( "{", end = '' , file=outfile) | |
ik = len(keys) | |
for k in keys: | |
newtxt = txt + "[" + k + "]" | |
ik = ik - 1 | |
type_i = type(o.__getitem__(k)) | |
print(" %s = " % k, end='', file=outfile) | |
introspect_obj(o.__getitem__(k), newtxt, indent+4) | |
if (ik > 0): | |
print(" , ", end='', file=outfile) | |
print( " } --[[ keys ]] ", end='', file=outfile) | |
else: | |
# list/tuple | |
try: length = len( o ) | |
except: length = -1 | |
if (length != -1): | |
# indexable? | |
if ("__getitem__" in __members__): | |
# print(" " * indent, end='', file=outfile) | |
# print(txt) | |
# lets not dump entire textures > 4k in ascii, m'kay :-) | |
print( " { ", end = '' , file=outfile) | |
if (not("pixels" in txt) or (length < 4 * 1024)): | |
for i in range(length): | |
print(" ", end='', file=outfile) | |
newtxt = txt + '[' + str(i) + ']' | |
# print(" -- %s " % newtxt, end='', file=outfile) | |
print(" [%d] = " % i, end='', file=outfile) | |
introspect_obj(o[i], newtxt, indent+4) | |
if (i < length -1): | |
print(" , ", end='', file=outfile) | |
print( " } --[[ array ]] " , end = '', file=outfile) | |
else: | |
# sets/nonindexable | |
# print(" " * indent, end='', file=outfile) | |
print( " { ", end = '' , file=outfile) | |
ic = len(o) | |
for i in o: | |
introspect_obj(i, None, indent+4) | |
ic = ic - 1 | |
if (ic > 0): | |
print(" , ", end='', file=outfile) | |
print( " } --[[ set ]] ", end='', file=outfile) | |
return | |
def dump_lua(fn, package, introspect, annotate): | |
global outfile | |
global annotate_file | |
outfile = open(fn, 'w+') | |
print ("%s = {" % package, end='', file=outfile) | |
annotate_file = annotate | |
introspect_obj(eval(introspect, globals(), locals()), introspect) | |
print ("}", file=outfile) | |
outfile.close() | |
class Export_Lua(bpy.types.Operator, ExportHelper): | |
'''Export secene as structured Lua Table''' | |
bl_idname = "export.lua" | |
bl_label = "Export Lua" | |
filename_ext = ".lua" | |
filter_glob = StringProperty(default="*.lua", options={'HIDDEN'}) | |
filepath = StringProperty(name="File Path", description="Filepath used for exporting the lua file", maxlen= 1024, default= "", subtype='FILE_PATH') | |
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True) | |
packageName = StringProperty(name="VarName", description="Name of variable to assign scene to.", maxlen=256,default="scene") | |
introspectName = StringProperty(name="Data", description="Data to introspect", maxlen=256, default="bpy.context.active_object") | |
annotateFlag = BoolProperty(name="Annotate", description="Annotate file with comments (makes it large!)", default=False) | |
@classmethod | |
def poll(cls, context): | |
return context.active_object != None | |
def execute(self, context): | |
dump_lua(self.filepath, self.packageName, self.introspectName, self.annotateFlag) | |
return {'FINISHED'} | |
### REGISTER ### | |
def menu_func(self, context): | |
self.layout.operator(Export_Lua.bl_idname, text="Lua (.lua)") | |
def register(): | |
bpy.utils.register_class(Export_Lua) | |
bpy.types.INFO_MT_file_export.append(menu_func) | |
#bpy.types.VIEW3D_PT_tools_objectmode.prepend(menu_func) | |
def unregister(): | |
bpy.utils.unregister_class(Export_Lua) | |
bpy.types.INFO_MT_file_export.remove(menu_func) | |
if __name__ == "__main__": | |
register() | |
# test call | |
bpy.ops.export.Lua('INVOKE_DEFAULT') |
No comments:
Post a Comment