Browse Source

Working on the binary serializer

Panagiotis Christopoulos Charitos 6 years ago
parent
commit
d63c132d22

+ 712 - 687
src/anki/script/lua_glue_gen.py

@@ -13,769 +13,794 @@ import xml.etree.ElementTree as et
 identation_level = 0
 identation_level = 0
 out_file = None
 out_file = None
 
 
+
 def parse_commandline():
 def parse_commandline():
-	""" Parse the command line arguments """
+    """ Parse the command line arguments """
+
+    parser = optparse.OptionParser(usage="usage: %prog [options]", description="Create LUA bindings using XML")
 
 
-	parser = optparse.OptionParser(usage = "usage: %prog [options]", description = "Create LUA bindings using XML")
+    parser.add_option(
+        "-i", "--input", dest="inp", type="string", help="specify the XML files to parse. Seperate with :")
 
 
-	parser.add_option("-i", "--input", dest = "inp", type = "string",
-		help = "specify the XML files to parse. Seperate with :")
+    (options, args) = parser.parse_args()
 
 
-	(options, args) = parser.parse_args()
+    if not options.inp:
+        parser.error("argument is missing")
 
 
-	if not options.inp:
-		parser.error("argument is missing")
+    return options.inp.split(":")
 
 
-	return options.inp.split(":")
 
 
 def type_sig(value):
 def type_sig(value):
-	""" Calculate the signature of a type """
-	return hash(value)
+    """ Calculate the signature of a type """
+    return hash(value)
+
 
 
 def get_base_fname(path):
 def get_base_fname(path):
-	""" From path/to/a/file.ext return the "file" """
-	return os.path.splitext(os.path.basename(path))[0]
+    """ From path/to/a/file.ext return the "file" """
+    return os.path.splitext(os.path.basename(path))[0]
+
 
 
 def wglue(txt):
 def wglue(txt):
-	""" Write glue code to the output """
-	global out_file
-	global identation_level
-	out_file.write("%s%s\n" % ("\t" * identation_level, txt))
+    """ Write glue code to the output """
+    global out_file
+    global identation_level
+    out_file.write("%s%s\n" % ("\t" * identation_level, txt))
+
 
 
 def ident(number):
 def ident(number):
-	""" Increase or recrease identation for the wglue """
-	global identation_level
-	identation_level += number
+    """ Increase or recrease identation for the wglue """
+    global identation_level
+    identation_level += number
+
 
 
 def type_is_bool(type):
 def type_is_bool(type):
-	""" Check if a type is boolean """
+    """ Check if a type is boolean """
+
+    return type == "Bool" or type == "bool"
 
 
-	return type == "Bool" or type == "bool"
 
 
 def type_is_number(type):
 def type_is_number(type):
-	""" Check if a type is number """
+    """ Check if a type is number """
+
+    numbers = [
+        "U8", "U16", "U32", "U64", "I8", "I16", "I32", "I64", "U", "I", "PtrSize", "F32", "F64", "int", "unsigned",
+        "unsigned int", "short", "unsigned short", "uint", "float", "double"
+    ]
 
 
-	numbers = ["U8", "U16", "U32", "U64", "I8", "I16", "I32", "I64", "U", "I", "PtrSize", "F32", "F64", \
-		"int", "unsigned", "unsigned int", "short", "unsigned short", "uint", "float", "double"]
+    it_is = False
+    for num in numbers:
+        if num == type:
+            it_is = True
+            break
 
 
-	it_is = False
-	for num in numbers:
-		if num == type:
-			it_is = True
-			break
+    return it_is
 
 
-	return it_is
 
 
 def parse_type_decl(arg_txt):
 def parse_type_decl(arg_txt):
-	""" Parse an arg text """
+    """ Parse an arg text """
 
 
-	tokens = arg_txt.split(" ")
-	tokens_size = len(tokens)
+    tokens = arg_txt.split(" ")
+    tokens_size = len(tokens)
 
 
-	type = tokens[tokens_size - 1]
-	type_len = len(type)
-	is_ptr = False
-	is_ref = False
-	if type[type_len - 1] == "&":
-		is_ref = True
-	elif type[type_len - 1] == "*":
-		is_ptr = True
+    type = tokens[tokens_size - 1]
+    type_len = len(type)
+    is_ptr = False
+    is_ref = False
+    if type[type_len - 1] == "&":
+        is_ref = True
+    elif type[type_len - 1] == "*":
+        is_ptr = True
 
 
-	if is_ref or is_ptr:
-		type = type[:-1]
+    if is_ref or is_ptr:
+        type = type[:-1]
 
 
-	is_const = False
-	if tokens[0] == "const":
-		is_const = True
+    is_const = False
+    if tokens[0] == "const":
+        is_const = True
+
+    return (type, is_ref, is_ptr, is_const)
 
 
-	return (type, is_ref, is_ptr, is_const)
 
 
 def ret(ret_el):
 def ret(ret_el):
-	""" Push return value """
-
-	if ret_el is None:
-		wglue("return 0;")
-		return
-
-	wglue("// Push return value")
-
-	type_txt = ret_el.text
-	(type, is_ref, is_ptr, is_const) = parse_type_decl(type_txt)
-
-	if is_ptr:
-		wglue("if(ANKI_UNLIKELY(ret == nullptr))")
-		wglue("{")
-		ident(1)
-		wglue("lua_pushstring(l, \"Glue code returned nullptr\");")
-		wglue("return -1;")
-		ident(-1)
-		wglue("}")
-		wglue("")
-
-	if type_is_bool(type):
-		wglue("lua_pushboolean(l, ret);")
-	elif type_is_number(type):
-		wglue("lua_pushnumber(l, lua_Number(ret));")
-	elif type == "char" or type == "CString":
-		wglue("lua_pushstring(l, &ret[0]);")
-	elif type == "Error":
-		wglue("if(ANKI_UNLIKELY(ret))")
-		wglue("{")
-		ident(1)
-		wglue("lua_pushstring(l, \"Glue code returned an error\");")
-		wglue("return -1;")
-		ident(-1)
-		wglue("}")
-		wglue("")
-		wglue("lua_pushnumber(l, lua_Number(ret));")
-	else:
-		if is_ptr or is_ref:
-		 	wglue("voidp = lua_newuserdata(l, sizeof(LuaUserData));")
-			wglue("ud = static_cast<LuaUserData*>(voidp);")
-			wglue("luaL_setmetatable(l, \"%s\");" % type)
-
-			wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % type)
-			if is_ptr:
-				wglue("ud->initPointed(&luaUserDataTypeInfo%s, const_cast<%s*>(ret));" % (type, type))
-			elif is_ref:
-				wglue("ud->initPointed(&luaUserDataTypeInfo%s, const_cast<%s*>(&ret));" % (type, type))
-		else:
-			wglue("size = LuaUserData::computeSizeForGarbageCollected<%s>();" % type)
-			wglue("voidp = lua_newuserdata(l, size);")
-			wglue("luaL_setmetatable(l, \"%s\");" % type)
-
-			wglue("ud = static_cast<LuaUserData*>(voidp);")
-			wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % type)
-			wglue("ud->initGarbageCollected(&luaUserDataTypeInfo%s);" % type)
-
-			wglue("::new(ud->getData<%s>()) %s(std::move(ret));" % (type, type))
-
-	wglue("")
-	wglue("return 1;")
+    """ Push return value """
+
+    if ret_el is None:
+        wglue("return 0;")
+        return
+
+    wglue("// Push return value")
+
+    type_txt = ret_el.text
+    (type, is_ref, is_ptr, is_const) = parse_type_decl(type_txt)
+
+    if is_ptr:
+        wglue("if(ANKI_UNLIKELY(ret == nullptr))")
+        wglue("{")
+        ident(1)
+        wglue("lua_pushstring(l, \"Glue code returned nullptr\");")
+        wglue("return -1;")
+        ident(-1)
+        wglue("}")
+        wglue("")
+
+    if type_is_bool(type):
+        wglue("lua_pushboolean(l, ret);")
+    elif type_is_number(type):
+        wglue("lua_pushnumber(l, lua_Number(ret));")
+    elif type == "char" or type == "CString":
+        wglue("lua_pushstring(l, &ret[0]);")
+    elif type == "Error":
+        wglue("if(ANKI_UNLIKELY(ret))")
+        wglue("{")
+        ident(1)
+        wglue("lua_pushstring(l, \"Glue code returned an error\");")
+        wglue("return -1;")
+        ident(-1)
+        wglue("}")
+        wglue("")
+        wglue("lua_pushnumber(l, lua_Number(ret));")
+    else:
+        if is_ptr or is_ref:
+            wglue("voidp = lua_newuserdata(l, sizeof(LuaUserData));")
+            wglue("ud = static_cast<LuaUserData*>(voidp);")
+            wglue("luaL_setmetatable(l, \"%s\");" % type)
+
+            wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % type)
+            if is_ptr:
+                wglue("ud->initPointed(&luaUserDataTypeInfo%s, const_cast<%s*>(ret));" % (type, type))
+            elif is_ref:
+                wglue("ud->initPointed(&luaUserDataTypeInfo%s, const_cast<%s*>(&ret));" % (type, type))
+        else:
+            wglue("size = LuaUserData::computeSizeForGarbageCollected<%s>();" % type)
+            wglue("voidp = lua_newuserdata(l, size);")
+            wglue("luaL_setmetatable(l, \"%s\");" % type)
+
+            wglue("ud = static_cast<LuaUserData*>(voidp);")
+            wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % type)
+            wglue("ud->initGarbageCollected(&luaUserDataTypeInfo%s);" % type)
+
+            wglue("::new(ud->getData<%s>()) %s(std::move(ret));" % (type, type))
+
+    wglue("")
+    wglue("return 1;")
+
 
 
 def arg(arg_txt, stack_index, index):
 def arg(arg_txt, stack_index, index):
-	""" Write the pop code for a single argument """
-
-	(type, is_ref, is_ptr, is_const) = parse_type_decl(arg_txt)
-
-	if type_is_bool(type) or type_is_number(type):
-		wglue("%s arg%d;" % (type, index))
-		wglue("if(ANKI_UNLIKELY(LuaBinder::checkNumber(l, %d, arg%d)))" % (stack_index, index))
-		wglue("{")
-		ident(1)
-		wglue("return -1;")
-		ident(-1)
-		wglue("}")
-	elif type == "char" or type == "CString":
-		wglue("const char* arg%d;" % index)
-		wglue("if(ANKI_UNLIKELY(LuaBinder::checkString(l, %d, arg%d)))" % (stack_index, index))
-		wglue("{")
-		ident(1)
-		wglue("return -1;")
-		ident(-1)
-		wglue("}")
-	else:
-		wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % type)
-		wglue("if(ANKI_UNLIKELY(LuaBinder::checkUserData(l, %d, luaUserDataTypeInfo%s, ud)))" % (stack_index, type))
-		wglue("{")
-		ident(1)
-		wglue("return -1;")
-		ident(-1)
-		wglue("}")
-		wglue("")
-
-		wglue("%s* iarg%d = ud->getData<%s>();" % (type, index, type))
-
-		if is_ptr:
-			wglue("%s arg%d(iarg%d);" % (arg_txt, index, index))
-		else:
-			wglue("%s arg%d(*iarg%d);" % (arg_txt, index, index))
+    """ Write the pop code for a single argument """
+
+    (type, is_ref, is_ptr, is_const) = parse_type_decl(arg_txt)
+
+    if type_is_bool(type) or type_is_number(type):
+        wglue("%s arg%d;" % (type, index))
+        wglue("if(ANKI_UNLIKELY(LuaBinder::checkNumber(l, %d, arg%d)))" % (stack_index, index))
+        wglue("{")
+        ident(1)
+        wglue("return -1;")
+        ident(-1)
+        wglue("}")
+    elif type == "char" or type == "CString":
+        wglue("const char* arg%d;" % index)
+        wglue("if(ANKI_UNLIKELY(LuaBinder::checkString(l, %d, arg%d)))" % (stack_index, index))
+        wglue("{")
+        ident(1)
+        wglue("return -1;")
+        ident(-1)
+        wglue("}")
+    else:
+        wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % type)
+        wglue("if(ANKI_UNLIKELY(LuaBinder::checkUserData(l, %d, luaUserDataTypeInfo%s, ud)))" % (stack_index, type))
+        wglue("{")
+        ident(1)
+        wglue("return -1;")
+        ident(-1)
+        wglue("}")
+        wglue("")
+
+        wglue("%s* iarg%d = ud->getData<%s>();" % (type, index, type))
+
+        if is_ptr:
+            wglue("%s arg%d(iarg%d);" % (arg_txt, index, index))
+        else:
+            wglue("%s arg%d(*iarg%d);" % (arg_txt, index, index))
 
 
 
 
 def args(args_el, stack_index):
 def args(args_el, stack_index):
-	""" Write the pop code for argument parsing and return the arg list """
+    """ Write the pop code for argument parsing and return the arg list """
 
 
-	if args_el is None:
-		return ""
+    if args_el is None:
+        return ""
 
 
-	wglue("// Pop arguments")
-	arg_index = 0
+    wglue("// Pop arguments")
+    arg_index = 0
 
 
-	# Do the work
-	args_str = ""
-	arg_index = 0
-	for arg_el in args_el.iter("arg"):
-		arg(arg_el.text, stack_index, arg_index)
-		args_str += "arg%d, " % arg_index
-		wglue("")
-		stack_index += 1
-		arg_index += 1
+    # Do the work
+    args_str = ""
+    arg_index = 0
+    for arg_el in args_el.iter("arg"):
+        arg(arg_el.text, stack_index, arg_index)
+        args_str += "arg%d, " % arg_index
+        wglue("")
+        stack_index += 1
+        arg_index += 1
 
 
-	if len(args_str) > 0:
-		args_str = args_str[:-2]
+    if len(args_str) > 0:
+        args_str = args_str[:-2]
+
+    return args_str
 
 
-	return args_str
 
 
 def count_args(args_el):
 def count_args(args_el):
-	""" Count the number of arguments """
+    """ Count the number of arguments """
+
+    if args_el is None:
+        return 0
 
 
-	if args_el is None:
-		return 0
+    count = 0
+    for arg_el in args_el.iter("arg"):
+        count += 1
 
 
-	count = 0
-	for arg_el in args_el.iter("arg"):
-		count += 1
+    return count
 
 
-	return count
 
 
 def check_args(args_el, bias):
 def check_args(args_el, bias):
-	""" Check number of args. Call that first because it throws error """
+    """ Check number of args. Call that first because it throws error """
 
 
-	if args_el is not None:
-		count = bias + count_args(args_el)
-	else:
-		count = bias
+    if args_el is not None:
+        count = bias + count_args(args_el)
+    else:
+        count = bias
+
+    wglue("if(ANKI_UNLIKELY(LuaBinder::checkArgsCount(l, %d)))" % count)
+    wglue("{")
+    ident(1)
+    wglue("return -1;")
+    ident(-1)
+    wglue("}")
+    wglue("")
 
 
-	wglue("if(ANKI_UNLIKELY(LuaBinder::checkArgsCount(l, %d)))" % count)
-	wglue("{")
-	ident(1)
-	wglue("return -1;")
-	ident(-1)
-	wglue("}")
-	wglue("")
 
 
 def get_meth_alias(meth_el):
 def get_meth_alias(meth_el):
-	""" Return the method alias """
-
-	meth_name = meth_el.get("name")
-
-	if meth_name == "operator+":
-		meth_alias = "__add"
-	elif meth_name == "operator-":
-		meth_alias = "__sub"
-	elif meth_name == "operator*":
-		meth_alias = "__mul"
-	elif meth_name == "operator/":
-		meth_alias = "__div"
-	elif meth_name == "operator==":
-		meth_alias = "__eq"
-	elif meth_name == "operator<":
-		meth_alias = "__lt"
-	elif meth_name == "operator<=":
-		meth_alias = "__le"
-	elif meth_name == "operator>":
-		meth_alias = "__gt"
-	elif meth_name == "operator>=":
-		meth_alias = "__ge"
-	elif meth_name == "operator=":
-		meth_alias = "copy"
-	else:
-		meth_alias = meth_name
-
-	meth_alias_txt = meth_el.get("alias")
-	if meth_alias_txt is not None:
-		meth_alias = meth_alias_txt
-
-	return meth_alias
+    """ Return the method alias """
+
+    meth_name = meth_el.get("name")
+
+    if meth_name == "operator+":
+        meth_alias = "__add"
+    elif meth_name == "operator-":
+        meth_alias = "__sub"
+    elif meth_name == "operator*":
+        meth_alias = "__mul"
+    elif meth_name == "operator/":
+        meth_alias = "__div"
+    elif meth_name == "operator==":
+        meth_alias = "__eq"
+    elif meth_name == "operator<":
+        meth_alias = "__lt"
+    elif meth_name == "operator<=":
+        meth_alias = "__le"
+    elif meth_name == "operator>":
+        meth_alias = "__gt"
+    elif meth_name == "operator>=":
+        meth_alias = "__ge"
+    elif meth_name == "operator=":
+        meth_alias = "copy"
+    else:
+        meth_alias = meth_name
+
+    meth_alias_txt = meth_el.get("alias")
+    if meth_alias_txt is not None:
+        meth_alias = meth_alias_txt
+
+    return meth_alias
+
 
 
 def write_local_vars():
 def write_local_vars():
-	wglue("LuaUserData* ud;")
-	wglue("(void)ud;")
-	wglue("void* voidp;")
-	wglue("(void)voidp;")
-	wglue("PtrSize size;")
-	wglue("(void)size;")
-	wglue("")
+    wglue("LuaUserData* ud;")
+    wglue("(void)ud;")
+    wglue("void* voidp;")
+    wglue("(void)voidp;")
+    wglue("PtrSize size;")
+    wglue("(void)size;")
+    wglue("")
+
 
 
 def method(class_name, meth_el):
 def method(class_name, meth_el):
-	""" Handle a method """
-
-	meth_name = meth_el.get("name")
-	meth_alias = get_meth_alias(meth_el)
-
-	wglue("/// Pre-wrap method %s::%s." % (class_name, meth_name))
-	wglue("static inline int pwrap%s%s(lua_State* l)" % (class_name, meth_alias))
-	wglue("{")
-	ident(1)
-	write_local_vars()
-
-	check_args(meth_el.find("args"), 1)
-
-	# Get this pointer
-	wglue("// Get \"this\" as \"self\"")
-	wglue("if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfo%s, ud))" % class_name)
-	wglue("{")
-	ident(1)
-	wglue("return -1;")
-	ident(-1)
-	wglue("}")
-	wglue("")
-	wglue("%s* self = ud->getData<%s>();" % (class_name, class_name))
-	wglue("")
-
-	args_str = args(meth_el.find("args"), 2)
-
-	# Return value
-	ret_txt = None
-	ret_el = meth_el.find("return")
-	if ret_el is not None:
-		ret_txt = ret_el.text
-
-	# Method call
-	wglue("// Call the method")
-	call = meth_el.find("overrideCall")
-	if call is not None:
-		call = call.text
-
-	if call is not None:
-		wglue("%s" % call)
-	else:
-		if ret_txt is None:
-			wglue("self->%s(%s);" % (meth_name, args_str))
-		else:
-			wglue("%s ret = self->%s(%s);" % (ret_txt, meth_name, args_str))
-
-	wglue("")
-	ret(ret_el)
-
-	ident(-1)
-	wglue("}")
-	wglue("")
-
-	# Write the actual function
-	wglue("/// Wrap method %s::%s." % (class_name, meth_name))
-	wglue("static int wrap%s%s(lua_State* l)" % (class_name, meth_alias))
-	wglue("{")
-	ident(1)
-	wglue("int res = pwrap%s%s(l);" % (class_name, meth_alias))
-	wglue("if(res >= 0)")
-	wglue("{")
-	ident(1)
-	wglue("return res;")
-	ident(-1)
-	wglue("}")
-	wglue("")
-	wglue("lua_error(l);")
-	wglue("return 0;")
-	ident(-1)
-	wglue("}")
-	wglue("")
+    """ Handle a method """
+
+    meth_name = meth_el.get("name")
+    meth_alias = get_meth_alias(meth_el)
+
+    wglue("/// Pre-wrap method %s::%s." % (class_name, meth_name))
+    wglue("static inline int pwrap%s%s(lua_State* l)" % (class_name, meth_alias))
+    wglue("{")
+    ident(1)
+    write_local_vars()
+
+    check_args(meth_el.find("args"), 1)
+
+    # Get this pointer
+    wglue("// Get \"this\" as \"self\"")
+    wglue("if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfo%s, ud))" % class_name)
+    wglue("{")
+    ident(1)
+    wglue("return -1;")
+    ident(-1)
+    wglue("}")
+    wglue("")
+    wglue("%s* self = ud->getData<%s>();" % (class_name, class_name))
+    wglue("")
+
+    args_str = args(meth_el.find("args"), 2)
+
+    # Return value
+    ret_txt = None
+    ret_el = meth_el.find("return")
+    if ret_el is not None:
+        ret_txt = ret_el.text
+
+    # Method call
+    wglue("// Call the method")
+    call = meth_el.find("overrideCall")
+    if call is not None:
+        call = call.text
+
+    if call is not None:
+        wglue("%s" % call)
+    else:
+        if ret_txt is None:
+            wglue("self->%s(%s);" % (meth_name, args_str))
+        else:
+            wglue("%s ret = self->%s(%s);" % (ret_txt, meth_name, args_str))
+
+    wglue("")
+    ret(ret_el)
+
+    ident(-1)
+    wglue("}")
+    wglue("")
+
+    # Write the actual function
+    wglue("/// Wrap method %s::%s." % (class_name, meth_name))
+    wglue("static int wrap%s%s(lua_State* l)" % (class_name, meth_alias))
+    wglue("{")
+    ident(1)
+    wglue("int res = pwrap%s%s(l);" % (class_name, meth_alias))
+    wglue("if(res >= 0)")
+    wglue("{")
+    ident(1)
+    wglue("return res;")
+    ident(-1)
+    wglue("}")
+    wglue("")
+    wglue("lua_error(l);")
+    wglue("return 0;")
+    ident(-1)
+    wglue("}")
+    wglue("")
+
 
 
 def static_method(class_name, meth_el):
 def static_method(class_name, meth_el):
-	""" Handle a static method """
-
-	meth_name = meth_el.get("name")
-	meth_alias = get_meth_alias(meth_el)
-
-	wglue("/// Pre-wrap static method %s::%s." % (class_name, meth_name))
-	wglue("static inline int pwrap%s%s(lua_State* l)" % (class_name, meth_alias))
-	wglue("{")
-	ident(1)
-	write_local_vars()
-
-	check_args(meth_el.find("args"), 0)
-
-	# Args
-	args_str = args(meth_el.find("args"), 1)
-
-	# Return value
-	ret_txt = None
-	ret_el = meth_el.find("return")
-	if ret_el is not None:
-		ret_txt = ret_el.text
-
-	# Method call
-	wglue("// Call the method")
-	if ret_txt is None:
-		wglue("%s::%s(%s);" % (class_name, meth_name, args_str))
-	else:
-		wglue("%s ret = %s::%s(%s);" % (ret_txt, class_name, meth_name, args_str))
-
-	wglue("")
-	ret(ret_el)
-
-	ident(-1)
-	wglue("}")
-	wglue("")
-
-	# Write the actual function
-	wglue("/// Wrap static method %s::%s." % (class_name, meth_name))
-	wglue("static int wrap%s%s(lua_State* l)" % (class_name, meth_alias))
-	wglue("{")
-	ident(1)
-	wglue("int res = pwrap%s%s(l);" % (class_name, meth_alias))
-	wglue("if(res >= 0)")
-	wglue("{")
-	ident(1)
-	wglue("return res;")
-	ident(-1)
-	wglue("}")
-	wglue("")
-	wglue("lua_error(l);")
-	wglue("return 0;")
-	ident(-1)
-	wglue("}")
-	wglue("")
+    """ Handle a static method """
+
+    meth_name = meth_el.get("name")
+    meth_alias = get_meth_alias(meth_el)
+
+    wglue("/// Pre-wrap static method %s::%s." % (class_name, meth_name))
+    wglue("static inline int pwrap%s%s(lua_State* l)" % (class_name, meth_alias))
+    wglue("{")
+    ident(1)
+    write_local_vars()
+
+    check_args(meth_el.find("args"), 0)
+
+    # Args
+    args_str = args(meth_el.find("args"), 1)
+
+    # Return value
+    ret_txt = None
+    ret_el = meth_el.find("return")
+    if ret_el is not None:
+        ret_txt = ret_el.text
+
+    # Method call
+    wglue("// Call the method")
+    if ret_txt is None:
+        wglue("%s::%s(%s);" % (class_name, meth_name, args_str))
+    else:
+        wglue("%s ret = %s::%s(%s);" % (ret_txt, class_name, meth_name, args_str))
+
+    wglue("")
+    ret(ret_el)
+
+    ident(-1)
+    wglue("}")
+    wglue("")
+
+    # Write the actual function
+    wglue("/// Wrap static method %s::%s." % (class_name, meth_name))
+    wglue("static int wrap%s%s(lua_State* l)" % (class_name, meth_alias))
+    wglue("{")
+    ident(1)
+    wglue("int res = pwrap%s%s(l);" % (class_name, meth_alias))
+    wglue("if(res >= 0)")
+    wglue("{")
+    ident(1)
+    wglue("return res;")
+    ident(-1)
+    wglue("}")
+    wglue("")
+    wglue("lua_error(l);")
+    wglue("return 0;")
+    ident(-1)
+    wglue("}")
+    wglue("")
+
 
 
 def constructor(constr_el, class_name, constructor_idx):
 def constructor(constr_el, class_name, constructor_idx):
-	""" Handle constructor """
+    """ Handle constructor """
 
 
-	wglue("/// Pre-wrap constructor for %s." % (class_name))
-	wglue("static inline int pwrap%sCtor%d(lua_State* l)" % (class_name, constructor_idx))
-	wglue("{")
-	ident(1)
-	write_local_vars()
+    wglue("/// Pre-wrap constructor for %s." % (class_name))
+    wglue("static inline int pwrap%sCtor%d(lua_State* l)" % (class_name, constructor_idx))
+    wglue("{")
+    ident(1)
+    write_local_vars()
 
 
-	check_args(constr_el.find("args"), 0)
+    check_args(constr_el.find("args"), 0)
 
 
-	# Args
-	args_str = args(constr_el.find("args"), 1)
+    # Args
+    args_str = args(constr_el.find("args"), 1)
 
 
-	# Create new userdata
-	wglue("// Create user data")
+    # Create new userdata
+    wglue("// Create user data")
 
 
-	wglue("size = LuaUserData::computeSizeForGarbageCollected<%s>();" % class_name)
-	wglue("voidp = lua_newuserdata(l, size);")
-	wglue("luaL_setmetatable(l, luaUserDataTypeInfo%s.m_typeName);" % class_name)
-	wglue("ud = static_cast<LuaUserData*>(voidp);")
-	wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % class_name)
-	wglue("ud->initGarbageCollected(&luaUserDataTypeInfo%s);" % class_name)
-	wglue("::new(ud->getData<%s>()) %s(%s);" % (class_name, class_name, args_str))
-	wglue("")
+    wglue("size = LuaUserData::computeSizeForGarbageCollected<%s>();" % class_name)
+    wglue("voidp = lua_newuserdata(l, size);")
+    wglue("luaL_setmetatable(l, luaUserDataTypeInfo%s.m_typeName);" % class_name)
+    wglue("ud = static_cast<LuaUserData*>(voidp);")
+    wglue("extern LuaUserDataTypeInfo luaUserDataTypeInfo%s;" % class_name)
+    wglue("ud->initGarbageCollected(&luaUserDataTypeInfo%s);" % class_name)
+    wglue("::new(ud->getData<%s>()) %s(%s);" % (class_name, class_name, args_str))
+    wglue("")
 
 
-	wglue("return 1;")
+    wglue("return 1;")
+
+    ident(-1)
+    wglue("}")
+    wglue("")
 
 
-	ident(-1)
-	wglue("}")
-	wglue("")
 
 
 def constructors(constructors_el, class_name):
 def constructors(constructors_el, class_name):
-	""" Wrap all constructors """
-
-	idx = 0
-	func_names_and_arg_counts = []
-
-	# Create the pre-wrap C functions
-	for constructor_el in constructors_el.iter("constructor"):
-		arg_count = count_args(constructor_el.find("args"))
-
-		# Iterate all arg counts and make sure there are no duplicates
-		for i in range(idx):
-			if func_names_and_arg_counts[i][1] == arg_count:
-				raise Exception("Every constructor overload should have a unique arg count. class: %s" % class_name)
-
-		constructor(constructor_el, class_name, idx)
-		func_names_and_arg_counts.append(["pwrap%sCtor%d" % (class_name, idx), arg_count])
-		idx += 1
-
-	if idx == 0:
-		raise Exception("Found no <constructor>")
-
-	# Create the landing function
-	wglue("/// Wrap constructors for %s." % class_name)
-	wglue("static int wrap%sCtor(lua_State* l)" % class_name)
-	wglue("{")
-	ident(1)
-	if idx == 1:
-		wglue("int res = pwrap%sCtor0(l);" % class_name)
-	else:
-		wglue("// Chose the right overload")
-		wglue("const int argCount = lua_gettop(l);")
-		wglue("int res = 0;")
-		wglue("switch(argCount)")
-		wglue("{")
-		for name_and_arg_count in func_names_and_arg_counts:
-			func_name = name_and_arg_count[0]
-			arg_count = name_and_arg_count[1]
-			wglue("case %d:" % arg_count)
-			wglue("res = %s(l); break;" % func_name)
-
-		wglue("default:")
-		wglue("lua_pushfstring(l, \"Wrong overloaded new. Wrong number of arguments: %d\", argCount);")
-		wglue("res = -1;")
-		wglue("}")
-	wglue("")
-
-	wglue("if(res >= 0)")
-	wglue("{")
-	ident(1)
-	wglue("return res;")
-	ident(-1)
-	wglue("}")
-	wglue("")
-	wglue("lua_error(l);")
-	wglue("return 0;")
-	ident(-1)
-	wglue("}")
-	wglue("")
+    """ Wrap all constructors """
+
+    idx = 0
+    func_names_and_arg_counts = []
+
+    # Create the pre-wrap C functions
+    for constructor_el in constructors_el.iter("constructor"):
+        arg_count = count_args(constructor_el.find("args"))
+
+        # Iterate all arg counts and make sure there are no duplicates
+        for i in range(idx):
+            if func_names_and_arg_counts[i][1] == arg_count:
+                raise Exception("Every constructor overload should have a unique arg count. class: %s" % class_name)
+
+        constructor(constructor_el, class_name, idx)
+        func_names_and_arg_counts.append(["pwrap%sCtor%d" % (class_name, idx), arg_count])
+        idx += 1
+
+    if idx == 0:
+        raise Exception("Found no <constructor>")
+
+    # Create the landing function
+    wglue("/// Wrap constructors for %s." % class_name)
+    wglue("static int wrap%sCtor(lua_State* l)" % class_name)
+    wglue("{")
+    ident(1)
+    if idx == 1:
+        wglue("int res = pwrap%sCtor0(l);" % class_name)
+    else:
+        wglue("// Chose the right overload")
+        wglue("const int argCount = lua_gettop(l);")
+        wglue("int res = 0;")
+        wglue("switch(argCount)")
+        wglue("{")
+        for name_and_arg_count in func_names_and_arg_counts:
+            func_name = name_and_arg_count[0]
+            arg_count = name_and_arg_count[1]
+            wglue("case %d:" % arg_count)
+            wglue("res = %s(l); break;" % func_name)
+
+        wglue("default:")
+        wglue("lua_pushfstring(l, \"Wrong overloaded new. Wrong number of arguments: %d\", argCount);")
+        wglue("res = -1;")
+        wglue("}")
+    wglue("")
+
+    wglue("if(res >= 0)")
+    wglue("{")
+    ident(1)
+    wglue("return res;")
+    ident(-1)
+    wglue("}")
+    wglue("")
+    wglue("lua_error(l);")
+    wglue("return 0;")
+    ident(-1)
+    wglue("}")
+    wglue("")
+
 
 
 def destructor(class_name):
 def destructor(class_name):
-	""" Create a destructor """
-
-	wglue("/// Wrap destructor for %s." % (class_name))
-	wglue("static int wrap%sDtor(lua_State* l)" % class_name)
-	wglue("{")
-	ident(1)
-	write_local_vars()
-
-	check_args(None, 1)
-
-	wglue("if(ANKI_UNLIKELY(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfo%s, ud)))" % class_name)
-	wglue("{")
-	ident(1)
-	wglue("return -1;")
-	ident(-1)
-	wglue("}")
-	wglue("");
-
-	wglue("if(ud->isGarbageCollected())")
-	wglue("{")
-	ident(1)
-	wglue("%s* inst = ud->getData<%s>();" % (class_name, class_name))
-	wglue("inst->~%s();" % class_name)
-	ident(-1)
-	wglue("}")
-	wglue("")
-
-	wglue("return 0;")
-
-	ident(-1)
-	wglue("}")
-	wglue("")
+    """ Create a destructor """
+
+    wglue("/// Wrap destructor for %s." % (class_name))
+    wglue("static int wrap%sDtor(lua_State* l)" % class_name)
+    wglue("{")
+    ident(1)
+    write_local_vars()
+
+    check_args(None, 1)
+
+    wglue("if(ANKI_UNLIKELY(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfo%s, ud)))" % class_name)
+    wglue("{")
+    ident(1)
+    wglue("return -1;")
+    ident(-1)
+    wglue("}")
+    wglue("")
+
+    wglue("if(ud->isGarbageCollected())")
+    wglue("{")
+    ident(1)
+    wglue("%s* inst = ud->getData<%s>();" % (class_name, class_name))
+    wglue("inst->~%s();" % class_name)
+    ident(-1)
+    wglue("}")
+    wglue("")
+
+    wglue("return 0;")
+
+    ident(-1)
+    wglue("}")
+    wglue("")
+
 
 
 def class_(class_el):
 def class_(class_el):
-	""" Create a class """
-
-	class_name = class_el.get("name")
-
-	# Write serializer
-	serialize = class_el.get("serialize") is not None and class_el.get("serialize") == "true"
-	if serialize:
-		# Serialize
-		serialize_cb_name = "serialize%s" % class_name
-		wglue("/// Serialize %s" % class_name)
-		wglue("static void %s(LuaUserData& self, void* data, PtrSize& size)" % serialize_cb_name)
-		wglue("{")
-		ident(1)
-		wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
-		wglue("obj->serialize(data, size);")
-		ident(-1)
-		wglue("}")
-		wglue("")
-
-		# Deserialize
-		deserialize_cb_name = "deserialize%s" % class_name
-		wglue("/// De-serialize %s" % class_name)
-		wglue("static void %s(const void* data, LuaUserData& self)" % deserialize_cb_name)
-		wglue("{")
-		ident(1)
-		wglue("ANKI_ASSERT(data);")
-		wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
-		wglue("::new(obj) %s();" % class_name)
-		wglue("obj->deserialize(data);")
-		ident(-1)
-		wglue("}")
-		wglue("")
-	else:
-		serialize_cb_name = "nullptr"
-		deserialize_cb_name = "nullptr"
-
-	# Write the type info
-	wglue("LuaUserDataTypeInfo luaUserDataTypeInfo%s = {" % class_name)
-	ident(1)
-	wglue("%d, \"%s\", LuaUserData::computeSizeForGarbageCollected<%s>(), %s, %s"
-			% (type_sig(class_name), class_name, class_name, serialize_cb_name, deserialize_cb_name))
-	ident(-1)
-	wglue("};")
-	wglue("")
-
-	# Specialize the getDataTypeInfoFor
-	wglue("template<>")
-	wglue("const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<%s>()" % class_name)
-	wglue("{")
-	ident(1)
-	wglue("return luaUserDataTypeInfo%s;" % class_name)
-	ident(-1)
-	wglue("}")
-	wglue("")
-
-	# Constructor declarations
-	has_constructor = False
-	constructors_el = class_el.find("constructors")
-	if constructors_el is not None:
-		has_constructor = True
-		constructors(constructors_el, class_name)
-
-	# Destructor declarations
-	if has_constructor:
-		destructor(class_name)
-
-	# Methods LUA C functions declarations
-	meth_names_aliases = []
-	meths_el = class_el.find("methods")
-	if meths_el is not None:
-		for meth_el in meths_el.iter("method"):
-			is_static = meth_el.get("static")
-			is_static = is_static is not None and is_static == "1"
-
-			if is_static:
-				static_method(class_name, meth_el)
-			else:
-				method(class_name, meth_el)
-
-			meth_name = meth_el.get("name")
-			meth_alias = get_meth_alias(meth_el)
-			meth_names_aliases.append([meth_name, meth_alias, is_static])
-
-	# Start class declaration
-	wglue("/// Wrap class %s." % class_name)
-	wglue("static inline void wrap%s(lua_State* l)" % class_name)
-	wglue("{")
-	ident(1)
-	wglue("LuaBinder::createClass(l, &luaUserDataTypeInfo%s);" % class_name)
-
-	# Register constructor
-	if has_constructor:
-		wglue("LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfo%s.m_typeName, \"new\", wrap%sCtor);"
-				% (class_name, class_name))
-
-	# Register destructor
-	if has_constructor:
-		wglue("LuaBinder::pushLuaCFuncMethod(l, \"__gc\", wrap%sDtor);" % class_name)
-
-	# Register methods
-	if len(meth_names_aliases) > 0:
-		for meth_name_alias in meth_names_aliases:
-			meth_alias = meth_name_alias[1]
-			is_static = meth_name_alias[2]
-			if is_static:
-				wglue("LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfo%s.m_typeName, \"%s\", wrap%s%s);"
-						% (class_name, meth_alias, class_name, meth_alias))
-			else:
-				wglue("LuaBinder::pushLuaCFuncMethod(l, \"%s\", wrap%s%s);" % (meth_alias, class_name, meth_alias))
-
-	wglue("lua_settop(l, 0);")
-
-	ident(-1)
-	wglue("}")
-	wglue("")
+    """ Create a class """
+
+    class_name = class_el.get("name")
+
+    # Write serializer
+    serialize = class_el.get("serialize") is not None and class_el.get("serialize") == "true"
+    if serialize:
+        # Serialize
+        serialize_cb_name = "serialize%s" % class_name
+        wglue("/// Serialize %s" % class_name)
+        wglue("static void %s(LuaUserData& self, void* data, PtrSize& size)" % serialize_cb_name)
+        wglue("{")
+        ident(1)
+        wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
+        wglue("obj->serialize(data, size);")
+        ident(-1)
+        wglue("}")
+        wglue("")
+
+        # Deserialize
+        deserialize_cb_name = "deserialize%s" % class_name
+        wglue("/// De-serialize %s" % class_name)
+        wglue("static void %s(const void* data, LuaUserData& self)" % deserialize_cb_name)
+        wglue("{")
+        ident(1)
+        wglue("ANKI_ASSERT(data);")
+        wglue("%s* obj = self.getData<%s>();" % (class_name, class_name))
+        wglue("::new(obj) %s();" % class_name)
+        wglue("obj->deserialize(data);")
+        ident(-1)
+        wglue("}")
+        wglue("")
+    else:
+        serialize_cb_name = "nullptr"
+        deserialize_cb_name = "nullptr"
+
+    # Write the type info
+    wglue("LuaUserDataTypeInfo luaUserDataTypeInfo%s = {" % class_name)
+    ident(1)
+    wglue("%d, \"%s\", LuaUserData::computeSizeForGarbageCollected<%s>(), %s, %s" %
+          (type_sig(class_name), class_name, class_name, serialize_cb_name, deserialize_cb_name))
+    ident(-1)
+    wglue("};")
+    wglue("")
+
+    # Specialize the getDataTypeInfoFor
+    wglue("template<>")
+    wglue("const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<%s>()" % class_name)
+    wglue("{")
+    ident(1)
+    wglue("return luaUserDataTypeInfo%s;" % class_name)
+    ident(-1)
+    wglue("}")
+    wglue("")
+
+    # Constructor declarations
+    has_constructor = False
+    constructors_el = class_el.find("constructors")
+    if constructors_el is not None:
+        has_constructor = True
+        constructors(constructors_el, class_name)
+
+    # Destructor declarations
+    if has_constructor:
+        destructor(class_name)
+
+    # Methods LUA C functions declarations
+    meth_names_aliases = []
+    meths_el = class_el.find("methods")
+    if meths_el is not None:
+        for meth_el in meths_el.iter("method"):
+            is_static = meth_el.get("static")
+            is_static = is_static is not None and is_static == "1"
+
+            if is_static:
+                static_method(class_name, meth_el)
+            else:
+                method(class_name, meth_el)
+
+            meth_name = meth_el.get("name")
+            meth_alias = get_meth_alias(meth_el)
+            meth_names_aliases.append([meth_name, meth_alias, is_static])
+
+    # Start class declaration
+    wglue("/// Wrap class %s." % class_name)
+    wglue("static inline void wrap%s(lua_State* l)" % class_name)
+    wglue("{")
+    ident(1)
+    wglue("LuaBinder::createClass(l, &luaUserDataTypeInfo%s);" % class_name)
+
+    # Register constructor
+    if has_constructor:
+        wglue("LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfo%s.m_typeName, \"new\", wrap%sCtor);" %
+              (class_name, class_name))
+
+    # Register destructor
+    if has_constructor:
+        wglue("LuaBinder::pushLuaCFuncMethod(l, \"__gc\", wrap%sDtor);" % class_name)
+
+    # Register methods
+    if len(meth_names_aliases) > 0:
+        for meth_name_alias in meth_names_aliases:
+            meth_alias = meth_name_alias[1]
+            is_static = meth_name_alias[2]
+            if is_static:
+                wglue("LuaBinder::pushLuaCFuncStaticMethod(l, luaUserDataTypeInfo%s.m_typeName, \"%s\", wrap%s%s);" %
+                      (class_name, meth_alias, class_name, meth_alias))
+            else:
+                wglue("LuaBinder::pushLuaCFuncMethod(l, \"%s\", wrap%s%s);" % (meth_alias, class_name, meth_alias))
+
+    wglue("lua_settop(l, 0);")
+
+    ident(-1)
+    wglue("}")
+    wglue("")
+
 
 
 def function(func_el):
 def function(func_el):
-	""" Handle a plain function """
-
-	func_name = func_el.get("name")
-	func_alias = get_meth_alias(func_el)
-
-	wglue("/// Pre-wrap function %s." % func_name)
-	wglue("static inline int pwrap%s(lua_State* l)" % func_alias)
-	wglue("{")
-	ident(1)
-	write_local_vars()
-
-	check_args(func_el.find("args"), 0)
-
-	# Args
-	args_str = args(func_el.find("args"), 1)
-
-	# Return value
-	ret_txt = None
-	ret_el = func_el.find("return")
-	if ret_el is not None:
-		ret_txt = ret_el.text
-
-	# Call
-	wglue("// Call the function")
-	call = func_el.find("overrideCall")
-	if call is not None:
-		call = call.text
-
-	if call is not None:
-		wglue("%s" % call)
-	else:
-		if ret_txt is None:
-			wglue("%s(%s);" % (func_name, args_str))
-		else:
-			wglue("%s ret = %s(%s);" % (ret_txt, func_name, args_str))
-
-	wglue("")
-	ret(ret_el)
-
-	ident(-1)
-	wglue("}")
-	wglue("")
-
-	# Write the actual function
-	wglue("/// Wrap function %s." % func_name)
-	wglue("static int wrap%s(lua_State* l)" % func_alias)
-	wglue("{")
-	ident(1)
-	wglue("int res = pwrap%s(l);" % func_alias)
-	wglue("if(res >= 0)")
-	wglue("{")
-	ident(1)
-	wglue("return res;")
-	ident(-1)
-	wglue("}")
-	wglue("")
-	wglue("lua_error(l);")
-	wglue("return 0;")
-	ident(-1)
-	wglue("}")
-	wglue("")
+    """ Handle a plain function """
+
+    func_name = func_el.get("name")
+    func_alias = get_meth_alias(func_el)
+
+    wglue("/// Pre-wrap function %s." % func_name)
+    wglue("static inline int pwrap%s(lua_State* l)" % func_alias)
+    wglue("{")
+    ident(1)
+    write_local_vars()
+
+    check_args(func_el.find("args"), 0)
+
+    # Args
+    args_str = args(func_el.find("args"), 1)
+
+    # Return value
+    ret_txt = None
+    ret_el = func_el.find("return")
+    if ret_el is not None:
+        ret_txt = ret_el.text
+
+    # Call
+    wglue("// Call the function")
+    call = func_el.find("overrideCall")
+    if call is not None:
+        call = call.text
+
+    if call is not None:
+        wglue("%s" % call)
+    else:
+        if ret_txt is None:
+            wglue("%s(%s);" % (func_name, args_str))
+        else:
+            wglue("%s ret = %s(%s);" % (ret_txt, func_name, args_str))
+
+    wglue("")
+    ret(ret_el)
+
+    ident(-1)
+    wglue("}")
+    wglue("")
+
+    # Write the actual function
+    wglue("/// Wrap function %s." % func_name)
+    wglue("static int wrap%s(lua_State* l)" % func_alias)
+    wglue("{")
+    ident(1)
+    wglue("int res = pwrap%s(l);" % func_alias)
+    wglue("if(res >= 0)")
+    wglue("{")
+    ident(1)
+    wglue("return res;")
+    ident(-1)
+    wglue("}")
+    wglue("")
+    wglue("lua_error(l);")
+    wglue("return 0;")
+    ident(-1)
+    wglue("}")
+    wglue("")
+
 
 
 def main():
 def main():
-	""" Main function """
-
-	global out_file
-	filenames = parse_commandline()
-
-	for filename in filenames:
-		out_filename = get_base_fname(filename) + ".cpp"
-		out_file = open(out_filename, "w")
-
-		tree = et.parse(filename)
-		root = tree.getroot()
-
-		# Head
-		head = root.find("head")
-		if head is not None:
-			wglue("%s" % head.text)
-			wglue("")
-
-		# Classes
-		class_names = []
-		for cls in root.iter("classes"):
-			for cl in cls.iter("class"):
-				class_(cl)
-				class_names.append(cl.get("name"))
-
-		# Functions
-		func_names = []
-		for fs in root.iter("functions"):
-			for f in fs.iter("function"):
-				function(f)
-				func_names.append(f.get("name"))
-
-		# Wrap function
-		wglue("/// Wrap the module.")
-		wglue("void wrapModule%s(lua_State* l)" % get_base_fname(filename))
-		wglue("{")
-		ident(1)
-		for class_name in class_names:
-			wglue("wrap%s(l);" % class_name)
-		for func_name in func_names:
-			wglue("LuaBinder::pushLuaCFunc(l, \"%s\", wrap%s);" % (func_name, func_name))
-		ident(-1)
-		wglue("}")
-		wglue("")
-
-		# Tail
-		tail = root.find("tail")
-		if tail is not None:
-			wglue("%s" % tail.text)
-			wglue("")
-
-		out_file.close()
+    """ Main function """
+
+    global out_file
+    filenames = parse_commandline()
+
+    for filename in filenames:
+        out_filename = get_base_fname(filename) + ".cpp"
+        out_file = open(out_filename, "w")
+
+        tree = et.parse(filename)
+        root = tree.getroot()
+
+        # Head
+        head = root.find("head")
+        if head is not None:
+            wglue("%s" % head.text)
+            wglue("")
+
+        # Classes
+        class_names = []
+        for cls in root.iter("classes"):
+            for cl in cls.iter("class"):
+                class_(cl)
+                class_names.append(cl.get("name"))
+
+        # Functions
+        func_names = []
+        for fs in root.iter("functions"):
+            for f in fs.iter("function"):
+                function(f)
+                func_names.append(f.get("name"))
+
+        # Wrap function
+        wglue("/// Wrap the module.")
+        wglue("void wrapModule%s(lua_State* l)" % get_base_fname(filename))
+        wglue("{")
+        ident(1)
+        for class_name in class_names:
+            wglue("wrap%s(l);" % class_name)
+        for func_name in func_names:
+            wglue("LuaBinder::pushLuaCFunc(l, \"%s\", wrap%s);" % (func_name, func_name))
+        ident(-1)
+        wglue("}")
+        wglue("")
+
+        # Tail
+        tail = root.find("tail")
+        if tail is not None:
+            wglue("%s" % tail.text)
+            wglue("")
+
+        out_file.close()
+
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
-	main()
+    main()

+ 7 - 0
src/anki/shader_compiler/Common.h

@@ -7,12 +7,19 @@
 
 
 #include <anki/util/Logger.h>
 #include <anki/util/Logger.h>
 
 
+namespace anki
+{
+
 /// @addtogroup shader_compiler
 /// @addtogroup shader_compiler
 /// @{
 /// @{
 
 
+constexpr U32 MAX_SHADER_PROGRAM_INPUT_VARIABLES = 128;
+
 #define ANKI_SHADER_COMPILER_LOGI(...) ANKI_LOG(" SHC", NORMAL, __VA_ARGS__)
 #define ANKI_SHADER_COMPILER_LOGI(...) ANKI_LOG(" SHC", NORMAL, __VA_ARGS__)
 #define ANKI_SHADER_COMPILER_LOGE(...) ANKI_LOG(" SHC", ERROR, __VA_ARGS__)
 #define ANKI_SHADER_COMPILER_LOGE(...) ANKI_LOG(" SHC", ERROR, __VA_ARGS__)
 #define ANKI_SHADER_COMPILER_LOGW(...) ANKI_LOG(" SHC", WARNING, __VA_ARGS__)
 #define ANKI_SHADER_COMPILER_LOGW(...) ANKI_LOG(" SHC", WARNING, __VA_ARGS__)
 #define ANKI_SHADER_COMPILER_LOGF(...) ANKI_LOG(" SHC", FATAL, __VA_ARGS__)
 #define ANKI_SHADER_COMPILER_LOGF(...) ANKI_LOG(" SHC", FATAL, __VA_ARGS__)
 
 
 /// @}
 /// @}
+
+} // end namespace anki

+ 3 - 0
src/anki/shader_compiler/Glslang.h

@@ -23,8 +23,11 @@
 namespace anki
 namespace anki
 {
 {
 
 
+/// @addtogroup shader_compiler
+/// @{
 extern TBuiltInResource GLSLANG_LIMITS;
 extern TBuiltInResource GLSLANG_LIMITS;
 
 
 EShLanguage ankiToGlslangShaderType(ShaderType shaderType);
 EShLanguage ankiToGlslangShaderType(ShaderType shaderType);
+/// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 102 - 0
src/anki/shader_compiler/ShaderProgramBinary.h

@@ -3,4 +3,106 @@
 // Code licensed under the BSD License.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
+// WARNING: This file is auto generated.
+
 #pragma once
 #pragma once
+
+#include <anki/src/shader_compiler/Common.h>
+
+namespace anki
+{
+
+/// Shader program input variable.
+class ShaderProgramBinaryInput
+{
+public:
+	char* m_name;
+	U32 m_nameSize; ///< It includes the '\0' char.
+	U32 m_firstSpecializationConstantIndex; ///< It's MAX_U32 if it's not a constant.
+	Bool m_instanced;
+	ShaderVariableDataType m_dataType;
+
+	template<typename TSerializer>
+	void serialize(TSerializer& serializer) const
+	{
+		serializer.writeDynamicArray(m_name, m_nameSize);
+		serializer.writeValue(m_nameSize) serializer.writeValue(m_firstSpecializationConstantIndex)
+			serializer.writeValue(m_instanced) serializer.writeValue(m_dataType)
+	}
+};
+
+/// Shader program mutator.
+class ShaderProgramBinaryMutator
+{
+public:
+	char* m_name;
+	I32* m_values;
+	U32 m_nameSize;
+	U32 m_valueCount;
+
+	template<typename TSerializer>
+	void serialize(TSerializer& serializer) const
+	{
+		serializer.writeDynamicArray(m_name, m_nameSize);
+		serializer.writeDynamicArray(m_values, m_valueCount);
+		serializer.writeValue(m_nameSize) serializer.writeValue(m_valueCount)
+	}
+};
+
+/// ShaderProgramBinaryVariant class.
+class ShaderProgramBinaryVariant
+{
+public:
+	I32* m_mutatorValues;
+	U32 m_mutatorValueCount;
+	BitSet<MAX_SHADER_PROGRAM_INPUT_VARIABLES, U32> m_activeVariables;
+	U32 m_codeIndex;
+
+	template<typename TSerializer>
+	void serialize(TSerializer& serializer) const
+	{
+		serializer.writeDynamicArray(m_mutatorValues, m_mutatorValueCount);
+		serializer.writeValue(m_mutatorValueCount) serializer.writeValue(m_activeVariables)
+			serializer.writeValue(m_codeIndex)
+	}
+};
+
+/// ShaderProgramBinaryCode class.
+class ShaderProgramBinaryCode
+{
+public:
+	U8* m_binary;
+	U32 m_binarySize;
+
+	template<typename TSerializer>
+	void serialize(TSerializer& serializer) const
+	{
+		serializer.writeDynamicArray(m_binary, m_binarySize);
+		serializer.writeValue(m_binarySize)
+	}
+};
+
+/// ShaderProgramBinary class.
+class ShaderProgramBinary
+{
+public:
+	Array<U8, 8> m_magic;
+	ShaderProgramBinaryMutator* m_mutators;
+	ShaderProgramBinaryInput* m_inputVariables;
+	ShaderProgramBinaryCode* m_codeBlocks;
+	U32 m_mutatorCount;
+	U32 m_inputVariableCount;
+	U32 m_codeBlockCount;
+
+	template<typename TSerializer>
+	void serialize(TSerializer& serializer) const
+	{
+		serializer.writeArray(m_magic, 8) serializer.writeDynamicArray(m_mutators, m_mutatorCount);
+		serializer.writeDynamicArray(m_inputVariables, m_inputVariableCount);
+		serializer.writeDynamicArray(m_codeBlocks, m_codeBlockCount);
+		serializer.writeValue(m_mutatorCount) serializer.writeValue(m_inputVariableCount)
+			serializer.writeValue(m_codeBlockCount)
+	}
+};
+
+} // end namespace anki

+ 54 - 0
src/anki/shader_compiler/ShaderProgramBinary.xml

@@ -0,0 +1,54 @@
+<serializer>
+	<includes>
+		<include file="&lt;anki/src/shader_compiler/Common.h&gt;"/>
+	</includes>
+
+	<classes>
+		<class name="ShaderProgramBinaryInput" comment="Shader program input variable">
+			<members>
+				<member name="m_name" type="char" pointer="true" array_size="m_nameSize" />
+				<member name="m_nameSize" type="U32" comment="It includes the '\0' char" />
+				<member name="m_firstSpecializationConstantIndex" type="U32" comment="It's MAX_U32 if it's not a constant" />
+				<member name="m_instanced" type="Bool" />
+				<member name="m_dataType" type="ShaderVariableDataType" />
+			</members>
+		</class>
+
+		<class name="ShaderProgramBinaryMutator" comment="Shader program mutator">
+			<members>
+				<member name="m_name" type="char" pointer="true" array_size="m_nameSize" />
+				<member name="m_values" type="I32" pointer="true" array_size="m_valueCount" />
+				<member name="m_nameSize" type="U32" />
+				<member name="m_valueCount" type="U32" />
+			</members>
+		</class>
+
+		<class name="ShaderProgramBinaryVariant">
+			<members>
+				<member name="m_mutatorValues" type="I32" pointer="true" array_size="m_mutatorValueCount" />
+				<member name="m_mutatorValueCount" type="U32" />
+				<member name="m_activeVariables" type="BitSet&lt;MAX_SHADER_PROGRAM_INPUT_VARIABLES, U32&gt;" />
+				<member name="m_codeIndex" type="U32" />
+			</members>
+		</class>
+
+		<class name="ShaderProgramBinaryCode">
+			<members>
+				<member name="m_binary" type="U8" pointer="true" array_size="m_binarySize" />
+				<member name="m_binarySize" type="U32" />
+			</members>
+		</class>
+
+		<class name="ShaderProgramBinary">
+			<members>
+				<member name="m_magic" type="U8" array_size="8" />
+				<member name="m_mutators" type="ShaderProgramBinaryMutator" pointer="true" array_size="m_mutatorCount" />
+				<member name="m_inputVariables" type="ShaderProgramBinaryInput" pointer="true" array_size="m_inputVariableCount" />
+				<member name="m_codeBlocks" type="ShaderProgramBinaryCode" pointer="true" array_size="m_codeBlockCount" />
+				<member name="m_mutatorCount" type="U32" />
+				<member name="m_inputVariableCount" type="U32" />
+				<member name="m_codeBlockCount" type="U32" />
+			</members>
+		</class>
+	</classes>
+</serializer>

+ 9 - 0
src/anki/shader_compiler/ShaderProgramCompiler.h

@@ -4,3 +4,12 @@
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
 #pragma once
 #pragma once
+
+namespace anki
+{
+
+/// @addtogroup shader_compiler
+/// @{
+/// @}
+
+} // end namespace anki

+ 1 - 3
src/anki/shader_compiler/ShaderProgramParser.h

@@ -19,11 +19,9 @@ namespace anki
 class ShaderProgramParser;
 class ShaderProgramParser;
 class ShaderProgramParserVariant;
 class ShaderProgramParserVariant;
 
 
-/// @addtogroup resource
+/// @addtogroup shader_compiler
 /// @{
 /// @{
 
 
-constexpr U32 MAX_SHADER_PROGRAM_INPUT_VARIABLES = 128;
-
 /// @memberof ShaderProgramParser
 /// @memberof ShaderProgramParser
 class ShaderProgramParserMutator
 class ShaderProgramParserMutator
 {
 {

+ 1 - 1
src/anki/util/CMakeLists.txt

@@ -1,5 +1,5 @@
 set(SOURCES Assert.cpp Functions.cpp File.cpp Filesystem.cpp Memory.cpp System.cpp HighRezTimer.cpp ThreadPool.cpp
 set(SOURCES Assert.cpp Functions.cpp File.cpp Filesystem.cpp Memory.cpp System.cpp HighRezTimer.cpp ThreadPool.cpp
-	ThreadHive.cpp Hash.cpp Logger.cpp String.cpp StringList.cpp Tracer.cpp)
+	ThreadHive.cpp Hash.cpp Logger.cpp String.cpp StringList.cpp Tracer.cpp Serializer.cpp)
 
 
 if(LINUX OR ANDROID OR MACOS)
 if(LINUX OR ANDROID OR MACOS)
 	set(SOURCES ${SOURCES} HighRezTimerPosix.cpp FilesystemPosix.cpp ThreadPosix.cpp)
 	set(SOURCES ${SOURCES} HighRezTimerPosix.cpp FilesystemPosix.cpp ThreadPosix.cpp)

+ 21 - 0
src/anki/util/File.cpp

@@ -452,6 +452,27 @@ Error File::seek(PtrSize offset, FileSeekOrigin origin)
 	return err;
 	return err;
 }
 }
 
 
+PtrSize File::tell()
+{
+	ANKI_ASSERT(m_file);
+	ANKI_ASSERT(m_flags != FileOpenFlag::NONE);
+
+	if(m_type == Type::C)
+	{
+		return ftell(ANKI_CFILE);
+	}
+#if ANKI_OS_ANDROID
+	else if(m_type == Type::SPECIAL)
+	{
+		ANKI_ASSERT(0);
+	}
+#endif
+	else
+	{
+		ANKI_ASSERT(0);
+	}
+}
+
 Error File::identifyFile(const CString& filename,
 Error File::identifyFile(const CString& filename,
 	char* archiveFilename,
 	char* archiveFilename,
 	PtrSize archiveFilenameLength,
 	PtrSize archiveFilenameLength,

+ 3 - 0
src/anki/util/File.h

@@ -106,6 +106,9 @@ public:
 	/// @param origin Position used as reference for the offset
 	/// @param origin Position used as reference for the offset
 	ANKI_USE_RESULT Error seek(PtrSize offset, FileSeekOrigin origin);
 	ANKI_USE_RESULT Error seek(PtrSize offset, FileSeekOrigin origin);
 
 
+	/// Return the position indicator inside the file.
+	PtrSize tell();
+
 	/// The the size of the file.
 	/// The the size of the file.
 	PtrSize getSize() const;
 	PtrSize getSize() const;
 
 

+ 7 - 7
src/anki/util/Functions.h

@@ -34,6 +34,12 @@ namespace anki
 #define ANKI_STRINGIZE(a) _ANKI_STRINGIZE(a)
 #define ANKI_STRINGIZE(a) _ANKI_STRINGIZE(a)
 
 
 // ANKI_ENABLE_METHOD & ANKI_ENABLE_ARG trickery copied from Tick library
 // ANKI_ENABLE_METHOD & ANKI_ENABLE_ARG trickery copied from Tick library
+template<typename T, int N>
+struct DummyType
+{
+};
+
+#if defined(_MSC_VER)
 template<bool B>
 template<bool B>
 struct RequiresBool
 struct RequiresBool
 {
 {
@@ -54,12 +60,6 @@ struct PrivateEnum
 	};
 	};
 };
 };
 
 
-template<typename T, int N>
-struct DummyType
-{
-};
-
-#if defined(_MSC_VER)
 #	define ANKI_REQUIRES_BOOL(line, ...) RequiresUnwrap<decltype(RequiresBool<(__VA_ARGS__)>{}), line>::VALUE
 #	define ANKI_REQUIRES_BOOL(line, ...) RequiresUnwrap<decltype(RequiresBool<(__VA_ARGS__)>{}), line>::VALUE
 
 
 #	define ANKI_ENABLE_INTERNAL(line, ...) \
 #	define ANKI_ENABLE_INTERNAL(line, ...) \
@@ -223,7 +223,7 @@ inline void alignRoundDown(TAlignment alignment, TValue& value)
 template<typename Type>
 template<typename Type>
 inline Bool isAligned(PtrSize alignment, Type value)
 inline Bool isAligned(PtrSize alignment, Type value)
 {
 {
-	return ((PtrSize)value % alignment) == 0;
+	return (PtrSize(value) % alignment) == 0;
 }
 }
 
 
 template<typename T>
 template<typename T>

+ 79 - 0
src/anki/util/Serializer.cpp

@@ -0,0 +1,79 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/util/Serializer.h>
+
+namespace anki
+{
+
+Error BinarySerializer::alignFilePos(U32 alignment)
+{
+	ANKI_ASSERT(alignment <= ANKI_SAFE_ALIGNMENT);
+
+	if(!isAligned(alignment, m_filePos))
+	{
+		alignRoundUp(alignment, m_filePos);
+		ANKI_CHECK(m_file->seek(m_filePos, FileSeekOrigin::BEGINNING));
+	}
+
+	return Error::NONE;
+}
+
+Error BinarySerializer::writeArrayBasicType(const void* arr, PtrSize size, U32 alignment)
+{
+	ANKI_ASSERT(arr && size > 0);
+	check();
+
+	ANKI_CHECK(alignFilePos(alignment));
+
+	ANKI_CHECK(m_file->write(arr, size));
+	m_filePos += size;
+
+	check();
+	return Error::NONE;
+}
+
+Error BinarySerializer::writeDynamicArrayBasicType(const void* arr, PtrSize size, U32 alignment)
+{
+	ANKI_ASSERT(arr);
+	check();
+
+	// Write the array at the end of the file
+	void* pointerPos;
+	if(size == 0)
+	{
+		pointerPos = nullptr;
+	}
+	else
+	{
+		// Move file pos to a new place
+		const PtrSize oldFilePos = m_filePos;
+		m_filePos = m_eofPos;
+		ANKI_CHECK(alignFilePos(alignment));
+		ANKI_CHECK(m_file->seek(m_filePos, FileSeekOrigin::BEGINNING));
+		m_eofPos = m_filePos + size;
+
+		// Write data
+		ANKI_CHECK(m_file->write(arr, size));
+
+		// Store the pos
+		pointerPos = numberToPtr<void*>(m_filePos);
+
+		// Restore file pos
+		m_filePos = oldFilePos;
+		ANKI_CHECK(m_file->seek(m_filePos, FileSeekOrigin::BEGINNING));
+	}
+
+	// Write the pointer
+	ANKI_CHECK(alignFilePos(alignof(void*)));
+	ANKI_CHECK(m_file->write(&pointerPos, sizeof(pointerPos)));
+	m_filePos += sizeof(pointerPos);
+	ANKI_ASSERT(m_filePos <= m_eofPos);
+
+	check();
+	return Error::NONE;
+}
+
+} // end namespace anki

+ 111 - 0
src/anki/util/Serializer.h

@@ -0,0 +1,111 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/util/File.h>
+
+#pragma once
+
+namespace anki
+{
+
+/// @addtogroup util_file
+/// @{
+
+/// Serializes to binary files.
+class BinarySerializer : public NonCopyable
+{
+public:
+	/// Serialize a class.
+	template<typename T>
+	ANKI_USE_RESULT Error serialize(const T& x, GenericMemoryPoolAllocator<U8> tmpAllocator, File& file);
+
+	/// Write a single value. Can't call this directly.
+	template<typename T>
+	void writeValue(const T& x)
+	{
+		writeArray(&x, 1);
+	}
+
+	/// Write an array of int and float values. Can't call this directly.
+	template<typename T, ANKI_ENABLE(!std::is_integral<T>::value && !std::is_floating_point<T>::value)>
+	void writeArray(const T* arr, PtrSize size)
+	{
+		if(!m_err)
+		{
+			m_err = writeArrayComplexType(arr, size);
+		}
+	}
+
+	/// Write an array of complex types. Can't call this directly.
+	template<typename T, ANKI_ENABLE(std::is_integral<T>::value || std::is_floating_point<T>::value)>
+	void writeArray(const T* arr, PtrSize size)
+	{
+		if(!m_err)
+		{
+			m_err = writeArrayBasicType(arr, size * sizeof(T), alignof(T));
+		}
+	}
+
+	/// Write a pointer. Can't call this directly.
+	template<typename T>
+	void writePointer(const T* ptr)
+	{
+		writeDynamicArray(ptr, 1);
+	}
+
+	/// Write a dynamic array of int and float values. Can't call this directly.
+	template<typename T, ANKI_ENABLE(!std::is_integral<T>::value && !std::is_floating_point<T>::value)>
+	void writeDynamicArray(const T* arr, PtrSize size)
+	{
+		if(!m_err)
+		{
+			m_err = writeDynamicArrayComplexType(arr, size);
+		}
+	}
+
+	/// Write a dynamic array of complex types. Can't call this directly.
+	template<typename T, ANKI_ENABLE(std::is_integral<T>::value || std::is_floating_point<T>::value)>
+	void writeDynamicArray(const T* arr, PtrSize size)
+	{
+		if(!m_err)
+		{
+			m_err = writeDynamicArrayBasicType(arr, size * sizeof(T), alignof(T));
+		}
+	}
+
+private:
+	class Header;
+
+	File* m_file = nullptr;
+	PtrSize m_filePos; ///< The current file position. Should be the same as m_file->tell()
+	PtrSize m_eofPos; ///< A logical end of the file. Used for allocations.
+	Error m_err = Error::NONE;
+
+	static constexpr const char* MAGIC = "ANKIBIN1";
+
+	template<typename T>
+	ANKI_USE_RESULT Error writeArrayComplexType(const T* arr, PtrSize size);
+
+	ANKI_USE_RESULT Error writeArrayBasicType(const void* arr, PtrSize size, U32 alignment);
+
+	template<typename T>
+	ANKI_USE_RESULT Error writeDynamicArrayComplexType(const T* arr, PtrSize size);
+
+	ANKI_USE_RESULT Error writeDynamicArrayBasicType(const void* arr, PtrSize size, U32 alignment);
+
+	ANKI_USE_RESULT Error alignFilePos(U32 alignment);
+
+	void check()
+	{
+		ANKI_ASSERT(m_file && "Can't call this function");
+		ANKI_ASSERT(m_filePos == m_file->tell());
+		ANKI_ASSERT(m_filePos < m_eofPos);
+	}
+};
+/// @}
+
+} // end namespace anki
+
+#include <anki/util/Serializer.inl.h>

+ 109 - 0
src/anki/util/Serializer.inl.h

@@ -0,0 +1,109 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/util/Serializer.h>
+
+namespace anki
+{
+
+class alignas(ANKI_SAFE_ALIGNMENT) BinarySerializer::Header
+{
+public:
+	Array<U8, 8> m_magic;
+};
+
+template<typename T>
+Error BinarySerializer::serialize(const T& x, GenericMemoryPoolAllocator<U8> tmpAllocator, File& file)
+{
+	// Misc
+	m_file = &file;
+	m_err = Error::NONE;
+
+	// Write header
+	Header header = {};
+	memcpy(&header.m_magic[0], MAGIC, sizeof(header.m_magic));
+	ANKI_CHECK(m_file->write(&header, sizeof(header)));
+
+	// Set file pos
+	m_filePos = m_file->tell();
+	ANKI_ASSERT(isAligned(ANKI_SAFE_ALIGNMENT, m_filePos));
+	m_eofPos = m_filePos + sizeof(x);
+
+	// Finaly, serialize
+	writeValue(x);
+	if(m_err)
+	{
+		ANKI_UTIL_LOGE("There was a serialization error");
+	}
+
+	// Done
+	m_file = nullptr;
+	return m_err;
+}
+
+template<typename T>
+Error BinarySerializer::writeArrayComplexType(const T* arr, PtrSize size)
+{
+	ANKI_ASSERT(arr && size > 0);
+	check();
+
+	for(PtrSize i = 0; i < size; ++i)
+	{
+		ANKI_CHECK(alignFilePos(alignof(T)));
+		arr[i].serialize(*this);
+		ANKI_CHECK(m_err);
+	}
+
+	check();
+	return Error::NONE;
+}
+
+template<typename T>
+Error BinarySerializer::writeDynamicArrayComplexType(const T* arr, PtrSize size)
+{
+	ANKI_ASSERT(arr);
+	check();
+
+	const U32 alignment = alignof(T);
+
+	// Write the array at the end of the file
+	void* pointerPos;
+	if(size == 0)
+	{
+		pointerPos = nullptr;
+	}
+	else
+	{
+		// Move file pos to a new place
+		const PtrSize oldFilePos = m_filePos;
+		m_filePos = m_eofPos;
+		ANKI_CHECK(alignFilePos(alignment));
+		pointerPos = numberToPtr<void*>(m_filePos);
+		ANKI_CHECK(m_file->seek(m_filePos, FileSeekOrigin::BEGINNING));
+		m_eofPos = m_filePos + size * sizeof(arr[0]);
+
+		// Write data
+		for(PtrSize i = 0; i < size; ++i)
+		{
+			arr[i].serialize(*this);
+			ANKI_CHECK(m_err);
+		}
+
+		// Restore file pos
+		m_filePos = oldFilePos;
+		ANKI_CHECK(m_file->seek(m_filePos, FileSeekOrigin::BEGINNING));
+	}
+
+	// Write the pointer
+	ANKI_CHECK(alignFilePos(alignof(void*)));
+	ANKI_CHECK(m_file->write(&pointerPos, sizeof(pointerPos)));
+	m_filePos += sizeof(pointerPos);
+	ANKI_ASSERT(m_filePos <= m_eofPos);
+
+	check();
+	return Error::NONE;
+}
+
+} // end namespace anki

+ 2 - 0
src/anki/util/StdTypes.h

@@ -73,6 +73,8 @@ constexpr F64 MIN_F64 = -std::numeric_limits<F64>::max();
 using Bool = bool; ///< 1 byte boolean type. The same as C++'s bool.
 using Bool = bool; ///< 1 byte boolean type. The same as C++'s bool.
 static_assert(sizeof(bool) == 1, "Wrong size for bool");
 static_assert(sizeof(bool) == 1, "Wrong size for bool");
 
 
+using Bool32 = I32;
+
 using Second = F64; ///< The base time unit is second.
 using Second = F64; ///< The base time unit is second.
 constexpr Second MAX_SECOND = MAX_F64;
 constexpr Second MAX_SECOND = MAX_F64;
 constexpr Second MIN_SECOND = MIN_F64;
 constexpr Second MIN_SECOND = MIN_F64;

+ 196 - 0
src/anki/util/serializer.py

@@ -0,0 +1,196 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+# All rights reserved.
+# Code licensed under the BSD License.
+# http://www.anki3d.org/LICENSE
+
+import optparse
+import xml.etree.ElementTree as et
+import os
+import copy
+
+
+class Context:
+    __slots__ = ["input_filenames", "output_filename", "output_file", "identation_level"]
+
+    def __init__(self):
+        self.input_filenames = None
+        self.output_filename = None
+        self.output_file = None
+        self.identation_level = 0
+
+
+ctx = Context()
+
+
+class MemberInfo:
+    __slots__ = ["name", "base_type", "array_size", "comment", "pointer"]
+
+    def __init__(self):
+        self.name = None
+        self.base_type = None
+        self.array_size = 1
+        self.comment = None
+        self.pointer = False
+
+
+def parse_commandline():
+    """ Parse the command line arguments """
+
+    parser = optparse.OptionParser(usage="usage: %prog [options]", description="Create serialization code using XML")
+
+    parser.add_option(
+        "-i", "--input", dest="inp", type="string", help="specify the XML files to parse. Seperate with :")
+
+    parser.add_option("-o", "--output", dest="out", type="string", help="specify the .h file to populate")
+
+    (options, args) = parser.parse_args()
+
+    if not options.inp or not options.out:
+        parser.error("argument is missing")
+
+    global ctx
+    ctx.input_filenames = options.inp.split(":")
+    ctx.output_filename = options.out
+
+
+def writeln(txt):
+    """ Write generated code to the output """
+    global ctx
+    ctx.output_file.write("%s%s\n" % ("\t" * ctx.identation_level, txt))
+
+
+def ident(number):
+    """ Increase or recrease identation for the writeln """
+    global ctx
+    ctx.identation_level += number
+
+
+def gen_class(root_el):
+    """ Parse a "class" element and generate the code. """
+
+    name = root_el.get("name")
+
+    # Write doxygen
+    if not root_el.get("comment"):
+        writeln("/// %s class." % name)
+    else:
+        writeln("/// %s." % root_el.get("comment"))
+
+    # Body start
+    writeln("class %s" % name)
+    writeln("{")
+    writeln("public:")
+
+    # Parse members
+    member_arr = []
+    members_el = root_el.find("members")
+    for member_el in members_el:
+        member = MemberInfo()
+
+        member.name = member_el.get("name")
+        member.base_type = member_el.get("type")
+
+        member.array_size = member_el.get("array_size")
+        if not member.array_size:
+            member.array_size = 1
+        elif str(member.array_size).isdigit():
+            member.array_size = int(member.array_size)
+
+        if member_el.get("pointer") and member_el.get("pointer") == "true":
+            member.pointer = True
+        else:
+            member.pointer = False
+
+        if member_el.get("comment"):
+            member.comment = member_el.get("comment")
+
+        member_arr.append(member)
+
+    # Write members
+    ident(1)
+    for member in member_arr:
+        if member.comment:
+            comment = "///< %s." % member.comment
+        else:
+            comment = ""
+
+        if member.pointer:
+            writeln("%s* %s; %s" % (member.base_type, member.name, comment))
+        elif member.array_size > 1:
+            writeln("Array<%s, %d> %s; %s" % (member.base_type, member.array_size, member.name, comment))
+        else:
+            writeln("%s %s; %s" % (member.base_type, member.name, comment))
+    ident(-1)
+
+    # Write the serializer code
+    writeln("")
+    ident(1)
+    writeln("template<typename TSerializer>")
+    writeln("void serialize(TSerializer& serializer) const")
+    writeln("{")
+    ident(1)
+
+    for member in member_arr:
+        if member.pointer and str(member.array_size) == 1:
+            writeln("serializer.writePointer(%s);" % member.name)
+        elif member.pointer:
+            writeln("serializer.writeDynamicArray(%s, %s);" % (member.name, member.array_size))
+        elif member.array_size > 1:
+            writeln("serializer.writeArray(&%s[0], %d);" % (member.name, member.array_size))
+        else:
+            writeln("serializer.writeValue(%s);" % member.name)
+
+    ident(-1)
+    writeln("}")
+    ident(-1)
+
+    # Body end
+    writeln("};")
+    writeln("")
+
+
+def gen_file(filename):
+    """ Parse an XML file and generate the code. """
+
+    tree = et.parse(filename)
+    root = tree.getroot()
+
+    for incs in root.iter("includes"):
+        for inc in incs.iter("include"):
+            writeln("#include %s" % inc.get("file"))
+
+    writeln("")
+    writeln("namespace anki")
+    writeln("{")
+    writeln("")
+
+    for cls in root.iter("classes"):
+        for cl in cls.iter("class"):
+            gen_class(cl)
+
+    writeln("} // end namespace anki")
+
+
+def main():
+    parse_commandline()
+
+    ctx.output_file = open(ctx.output_filename, "w")
+    ctx.output_file.write("""// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// WARNING: This file is auto generated.
+
+#pragma once
+
+""")
+
+    for filename in ctx.input_filenames:
+        gen_file(filename)
+
+
+if __name__ == "__main__":
+    main()

+ 2 - 2
tests/util/HighRezTimer.cpp

@@ -3,8 +3,8 @@
 // Code licensed under the BSD License.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
-#include "tests/framework/Framework.h"
-#include "anki/util/HighRezTimer.h"
+#include <tests/framework/Framework.h>
+#include <anki/util/HighRezTimer.h>
 #include <chrono>
 #include <chrono>
 #include <thread>
 #include <thread>
 
 

+ 32 - 0
tests/util/Serializer.cpp

@@ -0,0 +1,32 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <tests/framework/Framework.h>
+#include <anki/util/Serializer.h>
+#include <tests/util/SerializerTest.h>
+
+ANKI_TEST(Util, BinarySerializer)
+{
+	File file;
+	ANKI_TEST_EXPECT_NO_ERR(file.open("serialized.bin", FileOpenFlag::WRITE | FileOpenFlag::BINARY));
+	BinarySerializer serializer;
+
+	ClassB b;
+	b.m_array[0] = 2;
+	b.m_array[1] = 3;
+	b.m_array[2] = 4;
+	Array<U32, 3> bDarr = {{0xFF12EE34, 0xAA12BB34, 0xCC12DD34}};
+	b.m_darraySize = bDarr.getSize();
+	b.m_darray = &bDarr[0];
+
+	ClassA a;
+	a.m_array[0] = 123;
+	a.m_array[1] = 56;
+	a.m_u32 = 1;
+	a.m_u64 = 0x123456789ABCDEFF;
+	a.m_darray = &b;
+
+	ANKI_TEST_EXPECT_NO_ERR(serializer.serialize(a, file));
+}

+ 51 - 0
tests/util/SerializerTest.h

@@ -0,0 +1,51 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// WARNING: This file is auto generated.
+
+#pragma once
+
+#include <anki/util/Array.h>
+
+namespace anki
+{
+
+/// ClassB class.
+class ClassB
+{
+public:
+	Array<U8, 3> m_array;
+	U8 m_darraySize;
+	U32* m_darray;
+
+	template<typename TSerializer>
+	void serialize(TSerializer& serializer) const
+	{
+		serializer.writeArray(&m_array[0], 3);
+		serializer.writeValue(m_darraySize);
+		serializer.writeDynamicArray(m_darray, m_darraySize);
+	}
+};
+
+/// ClassA class.
+class ClassA
+{
+public:
+	Array<U8, 2> m_array;
+	U32 m_u32;
+	U64 m_u64;
+	ClassB* m_darray;
+
+	template<typename TSerializer>
+	void serialize(TSerializer& serializer) const
+	{
+		serializer.writeArray(&m_array[0], 2);
+		serializer.writeValue(m_u32);
+		serializer.writeValue(m_u64);
+		serializer.writeDynamicArray(m_darray, m_u32);
+	}
+};
+
+} // end namespace anki

+ 24 - 0
tests/util/SerializerTest.xml

@@ -0,0 +1,24 @@
+<serializer>
+	<includes>
+		<include file="&lt;anki/util/Array.h&gt;"/>
+	</includes>
+
+	<classes>
+		<class name="ClassB">
+			<members>
+				<member name="m_array" type="U8" array_size="3" />
+				<member name="m_darraySize" type="U8" />
+				<member name="m_darray" type="U32" pointer="true" array_size="m_darraySize" />
+			</members>
+		</class>
+
+		<class name="ClassA">
+			<members>
+				<member name="m_array" type="U8" array_size="2" />
+				<member name="m_u32" type="U32" />
+				<member name="m_u64" type="U64" />
+				<member name="m_darray" type="ClassB" pointer="true" array_size="m_u32" />
+			</members>
+		</class>
+	</classes>
+</serializer>

+ 1 - 1
tools/count_lines.sh

@@ -1 +1 @@
-wc -l `find ./src ./tests ./sandbox ./tools ./shaders ./samples -name '*.h' -o -name '*.hpp' -o -name '*.c' -o -name '*.cpp' -o -name '*.glsl' -o -name '*.py' -o -name '*.glslp'`
+wc -l `find ./src ./tests ./sandbox ./tools ./shaders ./samples -name '*.h' -o -name '*.hpp' -o -name '*.c' -o -name '*.cpp' -o -name '*.glsl' -o -name '*.py' -o -name '*.glslp' -o -name '*.xml' `