|
|
|
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') |