Created
December 2, 2011 11:43
-
-
Save johnfredcee/1422954 to your computer and use it in GitHub Desktop.
Dump Blender Scene as Lua via Introspection
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
| 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') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment