diff --git a/binding_generator/src/main.rs b/binding_generator/src/main.rs index f9a53b59..208d9bac 100644 --- a/binding_generator/src/main.rs +++ b/binding_generator/src/main.rs @@ -21,6 +21,7 @@ struct GodotClass { api_type: String, singleton: bool, instanciable: bool, + is_reference: bool, constants: Map, methods: Vec } @@ -43,6 +44,7 @@ struct GodotArgument { name: String, #[serde(rename = "type")] _type: String, + has_default_value: bool, default_value: String } @@ -73,7 +75,7 @@ fn main() { let mut icalls: HashSet<(String, Vec)> = HashSet::new(); - for class in json { + for class in &json { // make this toggleable with a command line switch // if class.api_type == "tools" { // println!("{}", class.name); @@ -96,7 +98,7 @@ fn main() { let mut icall_implmentation = File::create((base_dir.to_string() + "impl/__icalls.cpp").as_str()).unwrap(); - icall_implmentation.write_all(generate_icall_implementation(&icalls).as_bytes()); + icall_implmentation.write_all(generate_icall_implementation(&json, &icalls).as_bytes()); } fn get_used_classes(class: &GodotClass) -> HashSet<&String> { @@ -187,9 +189,9 @@ fn generate_class_header(used_classes: &HashSet<&String>, class: &GodotClass) -> // default constructor - // { - // contents = contents + "\t" + strip_name(&class.name) + "();\n\n"; - // } + { + contents = contents + "\tstatic " + strip_name(&class.name) + "* _new();\n\n"; + } // pointer constructor @@ -203,7 +205,7 @@ fn generate_class_header(used_classes: &HashSet<&String>, class: &GodotClass) -> // contents = contents + "\t" + strip_name(&class.name) + "(const Variant& obj);\n\n"; // } - if class.base_class != "" { + if class.name != "Object" { contents = contents + "\tvoid _init();\n\n"; } @@ -284,7 +286,7 @@ fn generate_class_header(used_classes: &HashSet<&String>, class: &GodotClass) -> contents = contents + escape_cpp(&argument.name); - if argument.default_value != "" || has_default { + if argument.has_default_value || has_default { contents = contents + " = " + escape_default_arg(&argument._type, &argument.default_value).as_str(); has_default = true; }// else if has_default { @@ -374,11 +376,13 @@ fn generate_class_implementation(icalls: &mut HashSet<(String, Vec)>, us // default constructor - // { - // contents = contents + "" + strip_name(&class.name) + "::" + strip_name(&class.name) + "()\n{\n"; - // contents = contents + "\t\n"; - // contents = contents + "}\n\n"; - // } + { + contents = contents + strip_name(&class.name) + " *" + strip_name(&class.name) + "::_new()\n{\n"; + contents = contents + "\tgodot_class_constructor constructor = godot_get_class_constructor(\"" + class.name.as_str() + "\");\n"; + contents = contents + "\tif (!constructor) { return nullptr; }\n"; + contents = contents + "\treturn (" + strip_name(&class.name) + " *) constructor();\n"; + contents = contents + "}\n\n"; + } // pointer constructor @@ -399,7 +403,7 @@ fn generate_class_implementation(icalls: &mut HashSet<(String, Vec)>, us // contents = contents + "}\n\n\n"; // } - if class.base_class != "" { + if class.name != "Object" { contents = contents + "void " + strip_name(&class.name) + "::" + "_init()\n{\n"; contents = contents + "\t\n"; contents = contents + "}\n\n"; @@ -459,6 +463,10 @@ fn generate_class_implementation(icalls: &mut HashSet<(String, Vec)>, us if method.return_type != "void" { contents = contents + "return "; + + if !is_primitive(&method.return_type) && !is_core_type(&method.return_type) { + contents = contents + "(" + strip_name(&method.return_type) + " *) (Object *) "; + } } contents = contents + "((Object *) " + core_obj_name.as_str() + ")->callv(\"" + method.name.as_str() + "\", __args);\n"; @@ -482,7 +490,7 @@ fn generate_class_implementation(icalls: &mut HashSet<(String, Vec)>, us if is_core_type(t) || is_primitive(t) { t.clone() } else { - "Object".to_string() + t.clone() } } @@ -574,11 +582,12 @@ fn get_icall_name_ref(sig: (&String, &Vec)) -> String { fn generate_icall_header(icalls: &HashSet<(String, Vec)>) -> String { - fn return_type(t: &String) -> &str { + fn return_type(t: &String) -> String { if is_primitive(t) || is_core_type(t) { - t.as_str() + t.clone() } else { - "godot_object* " + let s = String::new() + t.as_str() + " *"; + s } } @@ -591,12 +600,29 @@ fn generate_icall_header(icalls: &HashSet<(String, Vec)>) -> String { contents = contents + "#include \n\n\n"; contents = contents + "#include \"core/CoreTypes.hpp\"\n"; - contents = contents + "#include \"Object.hpp\"\n\n\n"; + // contents = contents + "#include \"Object.hpp\"\n\n\n"; + + let mut types_used = HashSet::new(); + + for &(ref ret, ref args) in icalls { + if !is_primitive(ret) && !is_core_type(ret) { + types_used.insert(ret.clone()); + } + for arg in args { + if !is_core_type(&arg) && !is_primitive(&arg) { + types_used.insert(arg.clone()); + } + } + } + + for ref type_ in types_used { + contents = contents + "#include \"" + strip_name(type_) + ".hpp\"\n\n\n"; + } contents = contents + "using namespace godot;\n\n\n"; for &(ref ret, ref args) in icalls { - contents = contents + return_type(ret) + " " + get_icall_name_ref((ret, args)).as_str() + "(godot_method_bind *mb, godot_object *inst"; + contents = contents + return_type(ret).as_str() + " " + get_icall_name_ref((ret, args)).as_str() + "(godot_method_bind *mb, godot_object *inst"; for arg in args { contents = contents + ", "; if is_core_type(&arg) { @@ -616,16 +642,26 @@ fn generate_icall_header(icalls: &HashSet<(String, Vec)>) -> String { contents } -fn generate_icall_implementation(icalls: &HashSet<(String, Vec)>) -> String { +fn generate_icall_implementation(class_api: &Vec, icalls: &HashSet<(String, Vec)>) -> String { - fn return_type(t: &String) -> &str { + fn return_type(t: &String) -> String { if is_primitive(t) || is_core_type(t) { - t.as_str() + t.clone() } else { - "godot_object* " + let s = String::new() + t.as_str() + " *"; + s } } + let is_reference = |name: &String| { + for class in class_api { + if class.name.as_str() == name.as_str() { + return class.is_reference; + } + } + false + }; + let mut contents = String::new(); contents = contents + "#include \"__icalls.hpp\"\n"; @@ -638,7 +674,7 @@ fn generate_icall_implementation(icalls: &HashSet<(String, Vec)>) -> Str contents = contents + "using namespace godot;\n\n\n"; for &(ref ret, ref args) in icalls { - contents = contents + return_type(ret) + " " + get_icall_name_ref((ret, args)).as_str() + "(godot_method_bind *mb, godot_object *inst"; + contents = contents + return_type(ret).as_str() + " " + get_icall_name_ref((ret, args)).as_str() + "(godot_method_bind *mb, godot_object *inst"; let mut i = 0; for arg in args { contents = contents + ", "; @@ -658,7 +694,11 @@ fn generate_icall_implementation(icalls: &HashSet<(String, Vec)>) -> Str contents = contents + "{\n"; if ret != "void" { - contents = contents + "\t" + if !is_core_type(ret) && !is_primitive(ret) { "godot_object*" } else { strip_name(ret) } + " ret;\n"; + contents = contents + "\t" + strip_name(ret) + if !is_core_type(ret) && !is_primitive(ret) { " *" } else { "" } + " ret;\n"; + if !is_core_type(ret) && !is_primitive(ret) && is_reference(ret) { + println!("{} is ref", ret); + contents = contents + "\t" + "ret = " + strip_name(ret) + "::_new();\n"; + } } contents = contents + "\tconst void *args[" + if args.len() == 0 { "1" } else { "" } + "] = {\n"; diff --git a/include/godot_cpp/Godot.hpp b/include/godot_cpp/Godot.hpp index 5ee42e6e..43d97acc 100644 --- a/include/godot_cpp/Godot.hpp +++ b/include/godot_cpp/Godot.hpp @@ -9,6 +9,8 @@ #include #include +#include + namespace godot { @@ -21,8 +23,8 @@ namespace godot { #endif -#define GODOT_DLSCRIPT_INIT(arg) extern "C" void GD_EXPORT godot_dlscript_init(arg) -#define GODOT_DLSCRIPT_TERMINATE(arg) extern "C" void GD_EXPORT godot_dlscript_terminate(arg) +#define GODOT_NATIVE_INIT(arg) extern "C" void GD_EXPORT godot_native_init(arg) +#define GODOT_NATIVE_TERMINATE(arg) extern "C" void GD_EXPORT godot_native_terminate(arg) @@ -63,7 +65,7 @@ struct _ArgCast { template T *as(Object *obj) { - return (T *) godot_dlinstance_get_userdata(obj); + return (T *) godot_native_get_userdata(obj); } // instance and destroy funcs @@ -550,7 +552,7 @@ struct _PropertySetFunc { Variant *v = (Variant *) &value; - (obj->*(set_func->f))(*v); + (obj->*(set_func->f))(_ArgCast

::_arg_cast(*v)); } }; @@ -575,8 +577,92 @@ struct _PropertyGetFunc { + + + template -void register_property(char *name, void (T::*setter)(P), P (T::*getter)(), P default_value, godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, godot_property_hint hint = GODOT_PROPERTY_HINT_NONE) +struct _PropertyDefaultSetFunc { + P (T::*f); + static void _wrapped_setter(godot_object *object, void *method_data, void *user_data, godot_variant value) + { + _PropertyDefaultSetFunc *set_func = (_PropertyDefaultSetFunc *) method_data; + T *obj = (T *) user_data; + + Variant *v = (Variant *) &value; + + (obj->*(set_func->f)) = _ArgCast

::_arg_cast(*v); + } +}; + +template +struct _PropertyDefaultGetFunc { + P (T::*f); + static godot_variant _wrapped_getter(godot_object *object, void *method_data, void *user_data) + { + _PropertyDefaultGetFunc *get_func = (_PropertyDefaultGetFunc *) method_data; + T *obj = (T *) user_data; + + godot_variant var; + godot_variant_new_nil(&var); + + Variant *v = (Variant *) &var; + + *v = (obj->*(get_func->f)); + + return var; + } +}; + + +template +void register_property(char *name, P (T::*var), P default_value, godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") +{ + Variant def_val = default_value; + + usage = (godot_property_usage_flags) ((int) usage | GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE); + + if (def_val.get_type() == Variant::OBJECT) { + Object *o = def_val; + if (o && o->is_class("Resource")) { + hint = (godot_property_hint) ((int) hint | GODOT_PROPERTY_HINT_RESOURCE_TYPE); + hint_string = o->get_class(); + } + } + + godot_string *_hint_string = (godot_string*) &hint_string; + + godot_property_attributes attr = {}; + attr.type = def_val.get_type(); + attr.default_value = *(godot_variant *) &def_val; + attr.hint = hint; + attr.rset_type = rpc_mode; + attr.usage = usage; + attr.hint_string = *_hint_string; + + _PropertyDefaultSetFunc *wrapped_set = (_PropertyDefaultSetFunc *) malloc(sizeof(_PropertyDefaultSetFunc)); + wrapped_set->f = var; + + _PropertyDefaultGetFunc *wrapped_get = (_PropertyDefaultGetFunc *) malloc(sizeof(_PropertyDefaultGetFunc)); + wrapped_get->f = var; + + godot_property_set_func set_func = {}; + set_func.method_data = (void *) wrapped_set; + set_func.free_func = free; + set_func.set_func = &_PropertyDefaultSetFunc::_wrapped_setter; + + godot_property_get_func get_func = {}; + get_func.method_data = (void *) wrapped_get; + get_func.free_func = free; + get_func.get_func = &_PropertyDefaultGetFunc::_wrapped_getter; + + godot_script_register_property(T::___get_type_name(), name, &attr, set_func, get_func); +} + + + + +template +void register_property(char *name, void (T::*setter)(P), P (T::*getter)(), P default_value, godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED, godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT, godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") { Variant def_val = default_value; @@ -607,6 +693,40 @@ void register_property(char *name, void (T::*setter)(P), P (T::*getter)(), P def } +template +void register_signal(String name, Dictionary args = Dictionary()) +{ + godot_signal signal = {}; + signal.name = *(godot_string *)&name; + signal.num_args = args.size(); + signal.num_default_args = 0; + + signal.args = (godot_signal_argument*) godot_alloc(sizeof(godot_signal_argument) * signal.num_args); + memset((void *) signal.args, 0, sizeof(godot_signal_argument) * signal.num_args); + + + for (int i = 0; i < signal.num_args; i++) { + // Array entry = args[i]; + // String name = entry[0]; + String name = args.keys()[i]; + godot_string *_key = (godot_string *)&name; + godot_string_new(&signal.args[i].name); + godot_string_copy_string(&signal.args[i].name, _key); + + // if (entry.size() > 1) { + // signal.args[i].type = entry[1]; + // } + signal.args[i].type = args.values()[i]; + } + + godot_script_register_signal(T::___get_type_name(), &signal); + + for (int i = 0; i < signal.num_args; i++) { + godot_string_destroy(&signal.args[i].name); + } +} + + } #endif // GODOT_H