There are a few core types which don't have all important methods exposed to the C API.
The most "dramatic" ones are
godot_image: I only implemented basic contructors, height and width, load and save. It would be cool to have at least all methods that are exposed to varcall implemented here. (if you want to go further and include functions only available to C++ then that's cool as well).
godot_string: Basically only has a constructor, a way to get the data back out of it, equality and concatenation. The C++ class has a lot more functions that are also very important, (like String::num()). Also a function to get a char * would be nice, using wchar_t * can be a pain.
Other types have missing C functions as well, but those functions can be implemented in the language binding much easier than string and image.
Maybe there are more, but these are the ones I can think of right now. Probably all of the C wrapped core types lack functionality. Feel free to wrap the C++ classes as much as possible.
Also, there's no equivalent of GDScript's print() or C++'s print_line(). So currently it's not possible to write to the in-editor-console using DLScript. A godot_print() function that does that would be cool. Such a function would live in godot.h/.c
only really string methods are missing.
The rest is more or less complete, mostly thanks to @touilleMan and also @sheepandshepherd.
Also @cynicaldevil for the efforts of wrapping Image, but that was removed recently, so your changes are obsolete 馃檨
If there are any questions, message me on IRC or Discord
@karroffel I'm taking this! Thought I would comment here as well, so that there's no duplicate work.
@cynicaldevil today the module got renamed. You might want to git pull upstream master --rebase so you can migrate your changes.
I did a few tests with GDNative and I miss the str() GDScript function so much when I want to set a text in a Label. The C++ std way to convert a float to a string is cumbersome.
Links to the files in OP lead to 404.
Also what @DriNeo said.
Oh yeah, I updated this a while ago. The link should now be correct.
Hi @karroffel ,
I'm really interested to work on this issue this week (if you agree) :)
Would you mind to briefly explaining me the reason why Godot has ustring.h and godot_string.h ? I'm pretty new here and I am struggling to understand how Godot internals are related.
@ducdetronquito awesome!
Sure, core/ustring.h is the actual String that is used everywhere.
modules/gdnative/godot/godot_string.h is the GDNative wrapper for String so it can be used using a C interface.
So one wrapping would look like this:
You want to wrap bool match(const String &p_wildcard) const;, so the C wrapper would be
godot_bool godot_string_match(const godot_string *p_self, const godot_string *p_wildcard) {
const String *self = (const String *) p_self;
const String *wildcard = (const String *) p_wildcard;
return self->match(*wildcard);
}
The basic procedure is to cast the pointer of the C wrapper type to a pointer to the actual C++ type, then use the regular C++ methods and wrap the result in a C wrapper type again.
If you have any question, feel free to ping me on IRC or Discord or write me a mail.
Wow, thanks for your quick and clear answer !
I am going to work on this tonight :coffee:
@karroffel ,
The methods String::begins_with is declared with a parameter const char *p_string.
Just to be sure: I don't need to convert this pointer as it is valid for both C and C++, right?
Edit: Ok, the compiler does not yell at me, so I think I was right !
@ducdetronquito no for the one taking a const char * you don't need to convert it. For the other one taking a String you need to.
When there are overloaded methods you need to find a new name for each one though as C doesn't support overloaded functions.
Also I did not mention that you need to write GDAPI between return type and function name, but I guess you already noticed that from all the other functions in there.
Hi @karroffel ,
I have some syntax questions due to my lack of knowledge in C/C++: if you could help me on this, it would be cool :)
How would you implement default function parameter like for the String.format method ? I does not recall a way to do it in C...
I don't get how to convert a String聽to a godot_string T_T. If I am not wrong, String is a subclass of a Vector\
EDIT:
I tried a conversion from a String to a godot_string for the String::num_scientific method. It compiles, but do you think it is the correct way to do it ?
godot_string GDAPI godot_string_num_scientific(double num) {
String *tmp = new String();
*tmp = String::num_scientific(num);
const godot_string *result = (const godot_string *) tmp;
return *result;
}
Hi @ducdetronquito,
C does not have default arguments, so just leave it as a regular parameter. You can add a comment on top to show what the default value is. (alternatively you can make two versions of that procedure. One with both arguments and one without the default one, it's up to you).
Here's the tricky part about GDNative. Godot uses C++ but C++ is bad when it comes to portability (on the ABI level). So what GDNative does is define wrapper types in C that have the same size as the C++ types and then just let C++ write to that memory. For C++ it looks like a regular object and for C it looks like some garbage.
typedef struct godot_string {
uint8_t _dont_touch_that[8];
} godot_string;
So in order to use a godot_string as a String you need to cast the pointer to the C++ type. String *p = (String *) godot_string_pointer_here; and *p // This is now a String.
To create a new String you need to initialize the "C memory" with the C++ data. You use memnew_placement() for that.
godot_string GDAPI godot_string_format(const godot_string *p_self, const godot_variant *p_values, godot_string p_placeholder)
{
// create the "conversion pointers". Be careful what is a pointer and what is copy-by-value (e.g. placeholder)
const String *self = (const String *) p_self;
const Variant *values = (const Variant *) p_values;
String *ptr_placeholder = (String *) &p_placeholder; // here we take the address of the value because it's not a poitner
godot_string ret;
memnew_placement(&ret, String(self->format(*values, *ptr_placeholder)));
// memnew_placement(destination_pointer, Constructor!!! )
return ret;
}
godot_string GDAPI godot_string_num_scientific(double num) {
godot_string ret;
memnew_placement(&ret, String(String::num_scientific(num));
// *tmp = String::num_scientific(num);
// const godot_string *result = (const godot_string *) tmp;
//return *result;
return ret;
}
The problem is that if you cast to a C type pointer and dereference it then you bypass the ref-count system that String has, so you need to use memnew_placement() to respect that system
Thanks a lot, your explanation is really, really clear :)
I will continue to work on this today !
Most helpful comment
@karroffel I'm taking this! Thought I would comment here as well, so that there's no duplicate work.